PSI sics-cvs-psi_pre-ansto

This commit is contained in:
2003-06-13 00:00:00 +00:00
committed by Douglas Clowes
parent 2e3ddfb6c6
commit 3ffd0d8af4
1099 changed files with 318432 additions and 0 deletions

2722
.log Normal file

File diff suppressed because it is too large Load Diff

27
.rfl Normal file
View File

@ -0,0 +1,27 @@
1 14.0 1.0 -3.0 34.93 17.4662365.2f -120.3757635.2f 57.86 0.00 0.00
2 25.0 20.0 3.0 121.37 60.6874285.2f -161.7680215.2f 151.81 0.00 0.00
3 14.0 1.0 -1.0 30.08 15.0386245.2f -105.8243565.2f 57.33 0.00 0.00
4 13.0 1.0 0.0 26.43 13.2171475.2f -97.0895085.2f 62.61 0.00 0.00
5 13.0 1.0 -2.0 30.17 15.0827995.2f -114.8090905.2f 59.43 0.00 0.00
6 0.0 7.0 1.0 38.10 19.0499325.2f 168.9476015.2f 154.39 0.00 0.00
7 -1.0 7.0 1.0 39.00 19.4981695.2f 166.0153055.2f 154.70 0.00 0.00
8 1.0 7.0 1.0 37.31 18.6574575.2f 172.0074465.2f 154.08 0.00 0.00
9 1.0 2.0 2.0 13.43 6.7168745.2f 176.1939855.2f -170.37 0.00 0.00
1 14.0 1.0 -3.0 34.93 17.47 -120.38 57.86 0.00 0.00
2 25.0 20.0 3.0 121.37 60.69 -161.77 151.81 0.00 0.00
3 14.0 1.0 -1.0 30.08 15.04 -105.82 57.33 0.00 0.00
4 13.0 1.0 0.0 26.43 13.22 -97.09 62.61 0.00 0.00
5 13.0 1.0 -2.0 30.17 15.08 -114.81 59.43 0.00 0.00
6 0.0 7.0 1.0 38.10 19.05 168.95 154.39 0.00 0.00
7 -1.0 7.0 1.0 39.00 19.50 166.02 154.70 0.00 0.00
8 1.0 7.0 1.0 37.31 18.66 172.01 154.08 0.00 0.00
9 1.0 2.0 2.0 13.43 6.72 176.19 -170.37 0.00 0.00
1 14.0 1.0 -3.0 34.93 17.47 -120.38 57.86 0.00 0.00
2 25.0 20.0 3.0 121.37 60.69 -161.77 151.81 0.00 0.00
3 14.0 1.0 -1.0 30.08 15.04 -105.82 57.33 0.00 0.00
4 13.0 1.0 0.0 26.43 13.22 -97.09 62.61 0.00 0.00
5 13.0 1.0 -2.0 30.17 15.08 -114.81 59.43 0.00 0.00
6 0.0 7.0 1.0 38.10 19.05 168.95 154.39 0.00 0.00
7 -1.0 7.0 1.0 39.00 19.50 166.02 154.70 0.00 0.00
8 1.0 7.0 1.0 37.31 18.66 172.01 154.08 0.00 0.00
9 1.0 2.0 2.0 13.43 6.72 176.19 -170.37 0.00 0.00

344
A1931.c Normal file
View File

@ -0,0 +1,344 @@
/*-------------------------------------------------------------------------
This is the implementation file for a driver for the Risoe A1931a
temperature controller. This driver controls the device through a GPIB
interface.
copyright: see file COPYRIGHT
Mark Koennecke, February 2003
-------------------------------------------------------------------------*/
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <assert.h>
#include <unistd.h>
#include "fortify.h"
#include "sics.h"
#include "obpar.h"
#include "evcontroller.h"
#include "evcontroller.i"
#include "evdriver.i"
#include "gpibcontroller.h"
#include "A1931.h"
/*========================== private data structure ====================*/
typedef struct {
int sensor; /* the control sensor */
pGPIB gpib; /* the GPIB interface to use in order to talk to the thing*/
int gpibAddress; /* address on bus */
int devID; /* deviceID of the controller on the GPIB */
char errorBuffer[132]; /* a buffer for error messages from the thing*/
char commandLine[132]; /* buffer to keep the offending command line */
int errorCode; /* error indicator */
}A1931, *pA1931;
/*============================ defines ================================*/
#define COMMERROR -300
#define A1931ERROR -301
#define FILEERROR -302
/*====================================================================*/
static char *A1931comm(pEVDriver pData, char *command){
char buffer[256], *pPtr;
int status;
pA1931 self = NULL;
Tcl_DString reply;
self = (pA1931)pData->pPrivate;
assert(self);
/*
send
*/
strncpy(buffer,command,250);
strcat(buffer,"\n");
status = GPIBsend(self->gpib,self->devID,buffer,(int)strlen(buffer));
if(status < 0){
self->errorCode = COMMERROR;
GPIBerrorDescription(self->gpib,status,self->errorBuffer,131);
return NULL;
}
/*
read until > is found
*/
Tcl_DStringInit(&reply);
while(1){
pPtr = GPIBreadTillTerm(self->gpib,self->devID,10);
if(strstr(pPtr,"GPIB READ ERROR") != NULL){
free(pPtr);
self->errorCode = COMMERROR;
Tcl_DStringFree(&reply);
return NULL;
} else {
Tcl_DStringAppend(&reply,pPtr,-1);
if(strchr(pPtr,'>') != NULL){
/*
finished
*/
free(pPtr);
break;
}
free(pPtr);
}
}
pPtr = NULL;
pPtr = strdup(Tcl_DStringValue(&reply));
Tcl_DStringFree(&reply);
if(pPtr[0] == '#'){
/*
error
*/
self->errorCode = A1931ERROR;
strncpy(self->errorBuffer,pPtr,131);
free(pPtr);
return NULL;
}
return pPtr;
}
/*--------------------------------------------------------------------*/
static int A1931command(pEVDriver pData, char *command, char *replyBuffer,
int replyBufferLen){
pA1931 self = NULL;
char *pReply = NULL;
self = (pA1931)pData->pPrivate;
assert(self);
pReply = A1931comm(pData,command);
if(pReply != NULL){
strncpy(replyBuffer,pReply,replyBufferLen);
free(pReply);
return 1;
} else {
strncpy(replyBuffer,self->errorBuffer,replyBufferLen);
return 0;
}
}
/*====================================================================*/
static int A1931Init(pEVDriver pData){
pA1931 self = NULL;
self = (pA1931)pData->pPrivate;
assert(self);
self->devID = GPIBattach(self->gpib,0,self->gpibAddress,0,13,0,0);
if(self->devID < 0){
return 0;
}
return 1;
}
/*====================================================================*/
static int A1931Close(pEVDriver pData){
pA1931 self = NULL;
self = (pA1931)pData->pPrivate;
assert(self);
GPIBdetach(self->gpib,self->devID);
self->devID = 0;
return 1;
}
/*===================================================================*/
static int A1931Get(pEVDriver pData,float *fPos){
pA1931 self = NULL;
char buffer[132], command[50];
int status;
self = (pA1931)pData->pPrivate;
assert(self);
sprintf(command,"?TEMP%1.1d",self->sensor);
status = A1931command(pData,command,buffer,131);
if(!status){
return 0;
}
sscanf(buffer,"%f",fPos);
return 1;
}
/*=====================================================================*/
static int A1931Set(pEVDriver pData, float fNew){
pA1931 self = NULL;
char buffer[132], command[50];
int status;
self = (pA1931)pData->pPrivate;
assert(self);
sprintf(command,"SET%1.1d=%f",self->sensor,fNew);
status = A1931command(pData,command,buffer,131);
if(!status){
return 0;
}
return 1;
}
/*====================================================================*/
static int A1931error(pEVDriver pData, int *iCode, char *errBuff, int bufLen){
pA1931 self = NULL;
char pError[256];
self = (pA1931)pData->pPrivate;
assert(self);
*iCode = self->errorCode;
sprintf(pError,"ERROR: %s",self->errorBuffer);
strncpy(errBuff,pError,bufLen);
return 1;
}
/*====================================================================*/
static int A1931fix(pEVDriver pData, int iCode){
pA1931 self = NULL;
char pError[256];
self = (pA1931)pData->pPrivate;
assert(self);
if(iCode == COMMERROR){
GPIBclear(self->gpib,self->devID);
return DEVREDO;
}
return DEVFAULT;
}
/*=====================================================================*/
pEVDriver CreateA1931Driver(int argc, char *argv[]){
pEVDriver self = NULL;
pA1931 priv = NULL;
if(argc < 2){
return NULL;
}
/*
allocate space
*/
self = CreateEVDriver(argc,argv);
priv = (pA1931)malloc(sizeof(A1931));
if(self == NULL || priv == NULL){
return NULL;
}
memset(priv,0,sizeof(A1931));
self->pPrivate = priv;
self->KillPrivate = free;
/*
initialize
*/
priv->gpib = (pGPIB)FindCommandData(pServ->pSics,argv[0],"GPIB");
if(!priv->gpib){
DeleteEVDriver(self);
return NULL;
}
priv->sensor = 1;
priv->gpibAddress = atoi(argv[1]);
/*
initialize function pointers
*/
self->Send = A1931command;
self->Init = A1931Init;
self->Close = A1931Close;
self->GetValue = A1931Get;
self->SetValue = A1931Set;
self->GetError = A1931error;
self->TryFixIt = A1931fix;
return self;
}
/*=======================================================================*/
static int downloadFile(pA1931 self, FILE *fd){
char buffer[132], *pPtr;
int status;
while(1){
if(fgets(buffer,130,fd) == NULL){
self->errorCode = FILEERROR;
strcpy(self->errorBuffer,"Failed to read from file");
return 0;
}
if(strstr(buffer,"$END") != NULL){
break;
}
status = GPIBsend(self->gpib,self->devID,buffer,(int)strlen(buffer));
if(status < 0){
self->errorCode = COMMERROR;
GPIBerrorDescription(self->gpib,status,self->errorBuffer,131);
return 0;
}
pPtr = GPIBreadTillTerm(self->gpib,self->devID,10);
if(pPtr[0] == '#'){
self->errorCode = A1931ERROR;
strncpy(self->errorBuffer,pPtr,131);
strncpy(self->commandLine,buffer,131);
free(pPtr);
return 0;
}
free(pPtr);
usleep(50);
}
return 1;
}
/*=======================================================================*/
int A1931Action(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pEVControl pEV = NULL;
pA1931 self = NULL;
char buffer[256];
char error[132];
FILE *fd = NULL;
int status, iCode;
pEV = (pEVControl)pData;
assert(pEV);
self = (pA1931)pEV->pDriv->pPrivate;
assert(self);
if(argc > 1){
strtolower(argv[1]);
if(strcmp(argv[1],"sensor") == 0){
if(argc > 2){
/* set case */
if(!SCMatchRights(pCon,usUser)){
return 0;
}
self->sensor = atoi(argv[2]);
SCSendOK(pCon);
return 1;
} else {
/* get case */
sprintf(buffer,"%s.sensor = %d",argv[0],self->sensor);
SCWrite(pCon,buffer,eValue);
return 1;
}
}else if(strcmp(argv[1],"list") == 0){
sprintf(buffer,"%s.sensor = %d",argv[0],self->sensor);
SCWrite(pCon,buffer,eValue);
return EVControlWrapper(pCon,pSics,pData,argc,argv);
} else if(strcmp(argv[1],"file") == 0){
if(!SCMatchRights(pCon,usUser)){
return 0;
}
if(argc < 3){
SCWrite(pCon,"ERROR: need filename argument",eError);
return 0;
}
fd = fopen(argv[2],"r");
if(fd == NULL){
sprintf(buffer,"ERROR: failed to open %s", argv[2]);
SCWrite(pCon,buffer,eError);
return 0;
}
status = downloadFile(self,fd);
fclose(fd);
if(!status){
A1931error(pEV->pDriv,&iCode,error,131);
sprintf(buffer,"%s while transfering file", error);
SCWrite(pCon,buffer,eError);
sprintf(buffer,"Offending command: %s",self->commandLine);
SCWrite(pCon,buffer,eError);
return 0;
}
SCSendOK(pCon);
return 1;
}
}
return EVControlWrapper(pCon,pSics,pData,argc,argv);
}

20
A1931.h Normal file
View File

@ -0,0 +1,20 @@
/*-------------------------------------------------------------------------
This is the header file for a driver for the Risoe A1931a temperature
controller. This driver controls the device through a GPIB interface.
copyright: see file COPYRIGHT
Mark Koennecke, February 2003
-------------------------------------------------------------------------*/
#ifndef A1931A
#define A19131A
#include "sics.h"
pEVDriver CreateA1931Driver(int argc, char *argv[]);
int A1931Action(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif

115
Busy.c Normal file
View File

@ -0,0 +1,115 @@
/*------------------------------------------------------------------------
A busy flag module for SICS.
Mark Koennecke, July 2002
-------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include "fortify.h"
#include "sics.h"
/*----------------------------------------------------------------------*/
typedef struct BUSY__ {
pObjectDescriptor pDes;
int iBusy;
}Busy;
/*---------------------------------------------------------------------*/
busyPtr makeBusy(void){
busyPtr result = NULL;
result = (busyPtr)malloc(sizeof(Busy));
if(!result){
return NULL;
}
result->pDes = CreateDescriptor("BusyFlag");
if(!result->pDes){
free(result);
return NULL;
}
result->iBusy = 0;
return result;
}
/*---------------------------------------------------------------------*/
void killBusy(void *self){
busyPtr busy;
if(self != NULL){
busy = (busyPtr)self;
if(busy->pDes != NULL){
DeleteDescriptor(busy->pDes);
}
free(busy);
}
}
/*---------------------------------------------------------------------*/
void incrementBusy(busyPtr self){
assert(self != NULL);
self->iBusy++;
}
/*--------------------------------------------------------------------*/
void decrementBusy(busyPtr self){
assert(self != NULL);
self->iBusy--;
if(self->iBusy < 0){
self->iBusy = 0;
}
}
/*--------------------------------------------------------------------*/
void clearBusy(busyPtr self){
assert(self != NULL);
self->iBusy = 0;
}
/*--------------------------------------------------------------------*/
void setBusy(busyPtr self, int val){
assert(self != NULL);
self->iBusy = val;
}
/*--------------------------------------------------------------------*/
int isBusy(busyPtr self){
assert(self != NULL);
return self->iBusy;
}
/*--------------------------------------------------------------------*/
int BusyAction(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]){
busyPtr self = NULL;
char pBuffer[80];
self = (busyPtr)pData;
assert(self != NULL);
if(argc > 1){
strtolower(argv[1]);
if(usUser < SCGetRights(pCon)){
SCWrite(pCon,"ERROR: no privilege to manipulate busy flag",eError);
return 0;
}
if(strcmp(argv[1],"incr") == 0){
incrementBusy(self);
SCSendOK(pCon);
return 1;
} else if(strcmp(argv[1],"decr") == 0){
decrementBusy(self);
SCSendOK(pCon);
return 1;
} else if(strcmp(argv[1],"clear") == 0){
clearBusy(self);
SCSendOK(pCon);
return 1;
}
}
sprintf(pBuffer,"Busy = %d", isBusy(self));
SCWrite(pCon,pBuffer,eValue);
return 1;
}
/*---------------------------------------------------------------------*/
busyPtr findBusy(SicsInterp *pInter){
CommandList *pCom = NULL;
pCom = FindCommand(pInter,"busy");
if(pCom != NULL){
return (busyPtr)pCom->pData;
}
}

28
Busy.h Normal file
View File

@ -0,0 +1,28 @@
/*------------------------------------------------------------------------
A busy flag module for SICS.
Mark Koennecke, July 2002
-------------------------------------------------------------------------*/
#ifndef SICSBUSY
#define SICSBUSY
typedef struct BUSY__ *busyPtr;
busyPtr makeBusy(void);
void killBusy(void *self);
void incrementBusy(busyPtr self);
void decrementBusy(busyPtr self);
void clearBusy(busyPtr self);
void setBusy(busyPtr self, int val);
int isBusy(busyPtr self);
int BusyAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
busyPtr findBusy(SicsInterp *pInter);
#endif

41
Busy.w Normal file
View File

@ -0,0 +1,41 @@
\subsection{Busy}
This class implements a busy flag which should be set when the interpreter
is busy doing something, like scanning for instance. The primary use
is for AMOR where operations are possible while writing data. This is
not caught by the normal device executor logic. In the long run, this
should become the standard way to control access to the
interpreter. In order to ensure access control, a test for the busy
flag is included into the SCMatchRights procedure. The busy flag is
installed into the interpreter.
@o Busy.h @{
/*------------------------------------------------------------------------
A busy flag module for SICS.
Mark Koennecke, July 2002
-------------------------------------------------------------------------*/
#ifndef SICSBUSY
#define SICSBUSY
typedef struct BUSY__ *busyPtr;
busyPtr makeBusy(void);
void killBusy(void *self);
void incrementBusy(busyPtr self);
void decrementBusy(busyPtr self);
void clearBusy(busyPtr self);
void setBusy(busyPtr self, int val);
int isBusy(busyPtr self);
int BusyAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
busyPtr findBusy(SicsInterp *pInter);
#endif
@}

340
COPYRIGHT Normal file
View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

161
Components.txt Normal file
View File

@ -0,0 +1,161 @@
SICS components in this directory
1.) SICS core
- SCinter.* SICS-Interpreter
- Scommon.h common definitions
- conman.* Connection object and management
- devexec.* Device executor
- ifile.* options database
- interrupt.h Interrupt system
intserv.c
intcli.*
- macro.* link between Sics and Tcl
initcl.c
- network.* network protocoll handling
- obdes.* Object descriptor
- ofac.* Object factory, creates objects at startup
- passwd.* password database
- script.* some commands to access SICS internals from
Tcl-scripts.
- nserver.* server startup and closing, main loop
- servlog.* manages the server log
- nserver.c server main program
- interface.* object interface descriptions
- event.* SICS event description
- callback.* The callback system
- costa.* Command stack used for queing commands.
- ecode.* Text version of error codes.
- task.* Cooperative multitasker.
2.) SICS core Objects
- buffer.* LNS-RuenBueffer
- ruli.* RuenBueffer stack management
- configfu.h Prototype for some configuration commands
- status.* Status handling object
- sicsexit.* Exit command
- commandlog.* The commandlog
- danu.c The data file number management
- emon.* Environment control monitoring
- evcontroller.* General environment controller class.
- evdriver.* General environement controller driver.
- perfmon.* Performance measure.
- token.* The token system for access control.
- udpquieck.* send a UDP message when a data file changed.
3.) SICS Objects
- counter.* Single counter object
- drive.* Drive command
- motor.* logical motor
- mumo.* multiple motor object (SANS)
comentry.*
mumoconf.*
- o2t.* Omega2Theta variable for TOPSI
- selector.* Handles a crystal monochromator with energy
selvar.* and lambda variables
- sicsvar.* primitive text, float or integer variables
- histmem.* histogram memory object
- nxdata.c some general NeXus data storage utilities
and the DMC storage routine
- nxutil.* NeXus utility routines.
- velo.* The velocity selector
- amor2t.* The AMOR Reflectometer two-theta movement
- choco.* A generalized controller with driveable
- chadapter.* parameters realized in chadapter.
- dmc.c special command initialization for DMC
- faverage.* Special command to average FOCUS-TOF data
online for status display.
- fitcenter.* Rough fitting and driving to center of
peaks.
- fowrite.* FOCUS TOF NeXus file writing.
- hkl.* Four circle angle calculation and driving.
- hklscan.* Scanning in reciprocal space for 4-circle.
- integrate.* Gabe integrtaion of scanned peaks.
- itc4.* Special things for ITC4, ITC-503 temperature
controllers.
- mesure.* Measuring reflection list on a 4-circle.
- nextrics.* Writing NeXus files for TRICS in rotation
camera mode.
- optimse.* General automatic peak optimisation using
center-of-gravity.
- pimotor.* Physik Instrument DC-804 step motor controller,
a child of motor.
- sanswave.* wavelength calculation for SANS using a
velocity selector.
- scan.* General purpose scanning utility.
- scontroller.* Access a serial port directly using SICS
- serial.* ways.
- sps.* Dealing with Siemens Siematic SPS controllers.
Probably SINQ specific.
- varlog.* log an environment controller
- xytable.* A general purpose table of x-y values.
- a2t. * AMOR two theta movement
- amorstat.* AMOR status display support
- nxamor.* AMOR data file writing
- amorscan.* AMOR specific scan functions.
4.) SICS Hardware driver
- countdriv.* EL737 counter driver
- modriv.* EL734 motor driver
el734driv.c
el734dc.c
- bruker.c Driver for the Bruker Magnet
- simcter.c Simulated counter
- simdriv.c Simulated motor
- histsim.c Simualted histogram memory
- histdriv.c histogram driver general
- sinqhmdriv.c SinQ histogram memory driver
- velosim.c Simulated velocity selector
- velodornier.c Dornier velocity selector
- dilludriv.* Driver for the old dillution cryostat
- docho.* Dornier chopper control system
- itc4driv.* Driver for ITC-4 - ITC-503 temperature
controllers.
- ltc11.* Driver for the Kyocera LTC-11 temperature
controller.
- pipiezo.* Driver for a Physik Instrument Piezo motor
controller.
- simchop.* simulated chopper.
- simev.* simulated environment controller.
- tclev.v necessary code for defining a environment
controller driver in Tcl.
5.) Utility
some of these are freeware files from the net
- Dbg.* Don Libbes Tcl-Debugger
- bit.h Bit-Array handling macros
- defines.h, lld*.* Linked list package
- fortify.* memory debugging package
ufortify.*
- fupa.* helps interpreting object commands
- obpar.* manages array of object parameters
- splitter.* command analysis code
- strdup.*, string duplication
- strrepl.c string replacement
- stringdict.* a String Dictionary
- dynstring.* Dynamic Strings.
- sdynar.* Dynmaic array.
- uubuffer.* uuencode something into a buffer.
6.) Subdirectorys
- hardsup additional HW handling code
- tcl SICS commands implemented in Tcl
- user user documentation
- user/general general SICS commands
- user/DMC DMC specific commands
- status status display clients
- fourcircle four circle diffraction related stuff
- ninx The ILL program INX modified for NeXus

1206
Dbg.c Normal file

File diff suppressed because it is too large Load Diff

46
Dbg.h Normal file
View File

@ -0,0 +1,46 @@
/* Dbg.h - Tcl Debugger include file
Written by: Don Libes, NIST, 3/23/93
Design and implementation of this program was paid for by U.S. tax
dollars. Therefore it is public domain. However, the author and NIST
would appreciate credit if this program or parts of it are used.
*/
/* _DEBUG or _DBG is just too likely, use something more unique */
#ifndef _NIST_DBG
#define _NIST_DBG
#include "tcl.h"
typedef int (Dbg_InterProc) _ANSI_ARGS_((Tcl_Interp *interp));
typedef int (Dbg_IgnoreFuncsProc) _ANSI_ARGS_((
Tcl_Interp *interp,
char *funcname));
typedef void (Dbg_OutputProc) _ANSI_ARGS_((
Tcl_Interp *interp,
char *output));
EXTERN char *Dbg_VarName;
EXTERN char *Dbg_DefaultCmdName;
/* trivial interface, creates a "debug" command in your interp */
EXTERN int Dbg_Init _ANSI_ARGS_((Tcl_Interp *));
EXTERN void Dbg_On _ANSI_ARGS_((Tcl_Interp *interp,
int immediate));
EXTERN void Dbg_Off _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN char **Dbg_ArgcArgv _ANSI_ARGS_((int argc,char *argv[],
int copy));
EXTERN int Dbg_Active _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN Dbg_InterProc *Dbg_Interactor _ANSI_ARGS_((
Tcl_Interp *interp,
Dbg_InterProc *interactor));
EXTERN Dbg_IgnoreFuncsProc *Dbg_IgnoreFuncs _ANSI_ARGS_((
Tcl_Interp *interp,
Dbg_IgnoreFuncsProc *));
EXTERN Dbg_OutputProc *Dbg_Output _ANSI_ARGS_((
Tcl_Interp *interp,
Dbg_OutputProc *));
#endif /* _NIST_DBG */

64
Dbg_cmd.c Normal file
View File

@ -0,0 +1,64 @@
/* Dbg_cmd.c - Tcl Debugger default command, used if app writer wants a
quick and reasonable default.
Written by: Don Libes, NIST, 3/23/93
Design and implementation of this program was paid for by U.S. tax
dollars. Therefore it is public domain. However, the author and NIST
would appreciate credit if this program or parts of it are used.
*/
#include "tclInt.h"
#include "Dbg.h"
char *Dbg_DefaultCmdName = "debug";
/*ARGSUSED*/
static int
App_DebugCmd(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp;
int argc;
char **argv;
{
int now = 0; /* soon if 0, now if 1 */
if (argc > 3) goto usage;
argv++;
while (*argv) {
if (0 == strcmp(*argv,"-now")) {
now = 1;
argv++;
}
else break;
}
if (!*argv) {
if (now) {
Dbg_On(interp,1);
} else {
goto usage;
}
} else if (0 == strcmp(*argv,"0")) {
Dbg_Off(interp);
} else {
Dbg_On(interp,now);
}
return(TCL_OK);
usage:
interp->result = "usage: [[-now] 1|0]";
return TCL_ERROR;
}
int
Dbg_Init(interp)
Tcl_Interp *interp;
{
Tcl_CreateCommand(interp,Dbg_DefaultCmdName,App_DebugCmd,
(ClientData)0,(void (*)())0);
return TCL_OK;
}

84
HistDriv.i Normal file
View File

@ -0,0 +1,84 @@
#line 462 "histogram.w"
/*---------------------------------------------------------------------------
H I S T D R I V
internal header file which includes the definition of the Histogram memory
driver structure.
Mark Koennecke, April 1997
----------------------------------------------------------------------------*/
#ifndef SICSHISTDRIV
#define SICSHISTDRIV
#include "hmdata.h"
#line 89 "histogram.w"
typedef struct __HistDriver {
pHMdata data;
/* counting operations data */
CounterMode eCount;
float fCountPreset;
/* status flags */
int iReconfig;
int iUpdate;
/* interface functions */
int (*Configure)(pHistDriver self,
SConnection *pCon,
pStringDict pOpt,
SicsInterp *pSics);
int (*Start)(pHistDriver self,
SConnection *pCon);
int (*Halt)(pHistDriver self);
int (*GetCountStatus)(pHistDriver self,
SConnection *pCon);
int (*GetError)(pHistDriver self,
int *iCode,
char *perror,
int iErrlen);
int (*TryAndFixIt)(pHistDriver self,
int iCode);
int (*GetData)(pHistDriver self,
SConnection *pCon);
int (*GetHistogram)(pHistDriver self,
SConnection *pCon,
int i,
int iStart, int iEnd,
HistInt *pData);
int (*SetHistogram)(pHistDriver self,
SConnection *pCon,
int i,
int iStart, int iEnd,
HistInt *pData);
long (*GetMonitor)(pHistDriver self,
int i,
SConnection *pCon);
float (*GetTime)(pHistDriver self,
SConnection *pCon);
int (*Preset)(pHistDriver self,
SConnection *pCon,
HistInt iVal);
int (*Pause)(pHistDriver self,
SConnection *pCon);
int (*Continue)(pHistDriver self,
SConnection *pCon);
int (*FreePrivate)(pHistDriver self);
void *pPriv;
} HistDriver;
#line 474 "histogram.w"
#line 228 "histogram.w"
pHistDriver CreateHistDriver(pStringDict pDict);
void DeleteHistDriver(pHistDriver self);
int HistDriverConfig(pHistDriver self, pStringDict pOpt,
SConnection *pCon);
#line 475 "histogram.w"
#endif

100
HistMem.h Normal file
View File

@ -0,0 +1,100 @@
#line 435 "histogram.w"
/*--------------------------------------------------------------------------
H I S T M E M
header for the histogram memory object for SICS.
copyright: see implementation file.
Mark Koennecke, April 1997
-----------------------------------------------------------------------------*/
#ifndef SICSHISTMEM
#define SICSHISTMEM
#define MAXDIM 3
typedef struct __HistDriver *pHistDriver;
typedef struct __HistMem *pHistMem;
/*-------------------------------------------------------------------------*/
typedef int HistInt;
/*
32 bit integer on a DigitalUnix
*/
#line 9 "histogram.w"
typedef enum {
eHTransparent,
eHNormal,
eHTOF,
eHStrobo,
eHRPT,
ePSD,
eSANSTOF
} HistMode;
#line 36 "histogram.w"
typedef enum {
eOIgnore,
eOCeil,
eOCount,
eReflect
} OverFlowMode;
#line 455 "histogram.w"
/*--------------------------------------------------------------------------*/
#line 287 "histogram.w"
pHistMem CreateHistMemory(char *drivername);
void DeleteHistMemory(void *self);
#line 303 "histogram.w"
int HistGetOption(pHistMem self, char *name, char *result, int iResultLen);
int HistSetOption(pHistMem self, char *name, char *value);
int HistConfigure(pHistMem self, SConnection *pCon, SicsInterp *pSics);
#line 331 "histogram.w"
float GetHistPreset(pHistMem self);
int SetHistPreset(pHistMem self, float fVal);
CounterMode GetHistCountMode(pHistMem self);
int SetHistCountMode(pHistMem self, CounterMode eNew);
long GetHistMonitor(pHistMem self, int i, SConnection *pCon);
const float *GetHistTimeBin(pHistMem self, int *iLength);
int GetHistLength(pHistMem self);
int GetHistDim(pHistMem self, int iDim[MAXDIM], int *nDim);
float GetHistCountTime(pHistMem self,SConnection *pCon);
int HistDoCount(pHistMem self, SConnection *pCon);
int HistBlockCount(pHistMem self, SConnection *pCon);
void HistDirty(pHistMem self);
#line 361 "histogram.w"
int SetHistogram(pHistMem self, SConnection *pCon,
int i,int iStart, int iEnd, HistInt *lData);
int GetHistogram(pHistMem self, SConnection *pCon,
int i,int iStart, int iEnd, HistInt *lData, int iDataLen);
HistInt *GetHistogramPointer(pHistMem self,SConnection *pCon);
int GetHistogramDirect(pHistMem self, SConnection *pCon,
int i, int iStart, int iEnd,
HistInt *lData, int iDataLen);
int PresetHistogram(pHistMem self, SConnection *pCon, HistInt lVal);
#line 404 "histogram.w"
int MakeHistMemory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int HistAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#line 457 "histogram.w"
#endif

30
HistMem.i Normal file
View File

@ -0,0 +1,30 @@
#line 480 "histogram.w"
/*---------------------------------------------------------------------------
H I S T M E M -- Internal
internal header file which includes the definition of the Histogram memory
data structure.
Mark Koennecke, April 1997
----------------------------------------------------------------------------*/
#ifndef SICSHISTMEMINT
#define SICSHISTMEMINT
#line 250 "histogram.w"
typedef struct __HistMem {
pObjectDescriptor pDes;
int iAccess;
int iExponent;
pHistDriver pDriv;
int iInit;
pICountable pCountInt;
pICallBack pCall;
pStringDict pOption;
} HistMem;
#line 490 "histogram.w"
#endif

131
Makefile Normal file
View File

@ -0,0 +1,131 @@
#----------------------------------------------------------------------------
# Makefile for SICS
#
# Mark Koennecke 1996-2001
# Markus Zolliker March 2000: add tecs
#---------------------------------------------------------------------------
#------- comment or uncomment this if a fortified version is required.
# Note: A -DFORTIFY needs to be added to the CFLAGS as well.
#
#FORTIFYOBJ = fortify.o strdup.o
#----
FORTIFYOBJ =
#---------------------------------------------------------------------------
#==========================================================================
# assign if the National Instrument GPIB driver is available
#NI= -DHAVENI
#NIOBJ= nigpib.o
#NILIB=-lgpibenet
NI=
NIOBJ=
NILIB=
#----- comment or uncomment if a difrac version is required
# Do not forget to remove or add comments to ofac.c as well if changes
# were made here.
DIFOBJ=
DIFIL=
#DIFOBJ=difrac.o -Ldifrac -ldif -lfor
#----
#DIFOBJ=difrac.o -Ldifrac -ldif
#DIFIL= difrac.o
#---------------------------------------------------------------------------
COBJ = Sclient.o network.o ifile.o intcli.o $(FORTIFYOBJ)
SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
servlog.o sicvar.o nserver.o SICSmain.o \
sicsexit.o costa.o task.o $(FORTIFYOBJ)\
macro.o ofac.o obpar.o obdes.o drive.o status.o intserv.o \
devexec.o mumo.o mumoconf.o selector.o selvar.o fupa.o lld.o \
lld_blob.o buffer.o strrepl.o ruli.o lin2ang.o fomerge.o\
script.o o2t.o alias.o napi45.o nxdata.o stringdict.o sdynar.o\
histmem.o histdriv.o histsim.o sinqhmdriv.o interface.o callback.o \
event.o emon.o evcontroller.o evdriver.o simev.o perfmon.o \
danu.o itc4driv.o itc4.o nxdict.o nxsans.o varlog.o stptok.o nread.o \
dilludriv.o scan.o fitcenter.o telnet.o token.o scontroller.o serial.o \
tclev.o hkl.o integrate.o optimise.o dynstring.o nextrics.o nxutil.o \
mesure.o uubuffer.o serialwait.o commandlog.o sps.o udpquieck.o \
sanswave.o faverage.o bruker.o rmtrail.o fowrite.o ltc11.o \
simchop.o choco.o chadapter.o docho.o trim.o eurodriv.o scaldate.o \
hklscan.o xytable.o amor2t.o nxamor.o amorscan.o amorstat.o \
circular.o el755driv.o maximize.o sicscron.o tecsdriv.o sanscook.o \
tasinit.o tasutil.o t_rlp.o t_conv.o d_sign.o d_mod.o \
tasdrive.o tasscan.o synchronize.o definealias.o swmotor.o t_update.o \
hmcontrol.o userscan.o slsmagnet.o rs232controller.o lomax.o \
polterwrite.o fourlib.o motreg.o motreglist.o anticollider.o \
s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) ecb.o ecbdriv.o \
ecbcounter.o hmdata.o tdchm.o nxscript.o A1931.o frame.o
MOTOROBJ = motor.o el734driv.o simdriv.o el734dc.o pipiezo.o pimotor.o
COUNTEROBJ = countdriv.o simcter.o counter.o
DMCOBJ = dmc.o
VELOOBJ = velo.o velosim.o velodorn.o velodornier.o
.SUFFIXES:
.SUFFIXES: .tcl .htm .c .o
#----- comment or uncomment the following according to operating system
#------------- for Digital Unix
BINTARGET = bin
HDFROOT=/data/lnslib
CC=cc
EXTRA=
CFLAGS = -I$(HDFROOT)/include -Ihardsup -DHDF4 -DHDF5 -I. -std1 \
-check_bounds -g -warnprotos -c
#CFLAGS = -I$(HDFROOT)/include -DFORTIFY -DHDF4 -DHDF5 -Ihardsup -g \
# -std1 -warnprotos -c
LIBS = -L$(HDFROOT)/lib -Lhardsup -lhlib -Lmatrix -lmatrix -Ltecs \
-ltecsl -ltcl8.0 -lfor $(HDFROOT)/lib/libhdf5.a \
$(HDFROOT)/lib/libLNSmfhdf.a $(HDFROOT)/lib/libLNSdf.a \
$(HDFROOT)/lib/libLNSjpeg.a -lLNSz -lm -ll -lc
#------- for cygnus
#HDFROOT=../HDF411
#CC=gcc
#EXTRA=
#CFLAGS = -I$(HDFROOT)/include -Ihardsup -DFORTIFY -DCYGNUS -g -c
#LIBS= -L$(HDFROOT)/lib -Lhardsup -lhlib -ltcl80 \
# -lmfhdf -ldf -ljpeg -lz -lm
#---------- for linux
#BINTARGET=../../bin
#HDFROOT=$(SINQDIR)/linux
#CC=gcc
#CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 $(NI) -Ihardsup \
# -fwritable-strings -DCYGNUS -DNONINTF -g -c
#CFLAGS = -I$(HDFROOT)/include -DFORTIFY -DHDF4 -DHDF5 $(NI) -Ihardsup \
# -fwritable-strings -DCYGNUS -DNONINTF -g -c
#LIBS= -L$(HDFROOT)/lib -Lhardsup -Ltecs -ltecsl -Lmatrix -lmatrix -lhlib \
# $(NILIB) -ltcl -lhdf5 -lmfhdf -ldf -ljpeg -lz -lm -lg2c -ldl
#EXTRA=nintf.o
#---------------------------------
.c.o:
$(CC) $(CFLAGS) $*.c
all: $(BINTARGET)/SICServer
$(BINTARGET)/SICServer: $(SOBJ) $(MOTOROBJ) \
$(COUNTEROBJ) $(DMCOBJ) $(VELOOBJ) $(DIFIL) \
$(EXTRA) tecs/libtecsl.a hardsup/libhlib.a \
matrix/libmatrix.a
$(CC) -g -o SICServer \
$(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) $(DMCOBJ) \
$(VELOOBJ) $(DIFOBJ) $(EXTRA) $(LIBS)
cp SICServer $(BINTARGET)
clean:
- rm -f *.o
- rm -f $(BINTARGET)/SICServer
Dbg.o: Dbg.c
cc -g -I/data/koenneck/include -c Dbg.c
Dbg_cmd.o: Dbg_cmd.c

569
SCinter.c Normal file
View File

@ -0,0 +1,569 @@
/*---------------------------------------------------------------------------
Implementation file for the SICS-interpreter.
Mark Koennecke, November 1996
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
M. Zolliker, Sept 2000, introduced formal aliases, modifications marked M.Z
Mark Koennecke, August 2001, modified SicsWriteStatus to write motor
positions on demand.
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <string.h>
#include <tcl.h>
#include "fortify.h"
#include "sics.h"
#include "splitter.h"
#include "servlog.h"
#include "macro.h"
#include "interface.h"
#include "motor.h"
#include "obdes.h"
/* M.Z. */
#include "definealias.h"
#define MAXLEN 256
#define MAXPAR 100
/*--------------------------------------------------------------------------*/
SicsInterp *InitInterp(void)
{
SicsInterp *pInter = NULL;
int i;
pInter = (SicsInterp *)malloc(sizeof(SicsInterp));
if(!pInter)
{
SICSLogWrite("Error allocating memory for Interpreter",eInternal);
return NULL;
}
pInter->pCList = NULL;
pInter->AList.pFirst = NULL; /* M.Z. */
pInter->pTcl = (void *)MacroInit(pInter);
if(!pInter->pTcl)
{
free(pInter);
return NULL;
}
pInter->iDeleting = 0;
return pInter;
}
/*------------------------------------------------------------------------*/
int AddCommand(SicsInterp *pInterp, char *pName, ObjectFunc pFunc,
KillFunc pKFunc, void *pData)
{
CommandList *pNew = NULL;
char pBueffel[512];
assert(pName);
assert(pFunc);
assert(pInterp);
strcpy(pBueffel,pName);
strtolower(pBueffel);
RemoveAlias(&pInterp->AList,pBueffel); /* M.Z. */
if(FindCommand(pInterp,pBueffel) != NULL)
{
return 0;
}
/* new memory */
pNew = (CommandList *)malloc(sizeof(CommandList));
if(!pNew)
{
sprintf(pBueffel,
"Out of memory creating command - %s -", pName);
SICSLogWrite(pBueffel,eInternal);
return 0;
}
/* if no data given, initialise with Dummy struct */
if(!pData)
{
pData = (void *)CreateDummy(pBueffel);
if(!pKFunc)
{
pKFunc = KillDummy;
}
}
/* initialise datastructures */
pNew->pName = strdup(pBueffel);
pNew->OFunc = pFunc;
pNew->KFunc = pKFunc;
pNew->pData = pData;
pNew->pNext = pInterp->pCList;
if(pInterp->pCList)
{
pInterp->pCList->pPrevious = pNew;
}
pNew->pPrevious = NULL;
/* update headpointer */
pInterp->pCList = pNew;
return 1;
}
/*------------------------------------------------------------------------*/
int RemoveCommand(SicsInterp *pInterp, char *pName)
{
CommandList *pVictim = NULL;
char pBueffel[256];
assert(pInterp);
assert(pName);
strcpy(pBueffel,pName);
strtolower(pBueffel);
if(pInterp->iDeleting)
{
return 0;
}
/* find our victim */
pVictim = FindCommand(pInterp, pBueffel);
if(!pVictim)
return 0;
/* found, remove it */
/* kall KillFunction first */
if(pVictim->KFunc)
{
pVictim->KFunc(pVictim->pData);
}
/* delete and unlink data */
if(pVictim->pName)
{
free(pVictim->pName);
}
if(pVictim->pPrevious)
{
pVictim->pPrevious->pNext = pVictim->pNext;
}
if(pVictim->pNext)
{
pVictim->pNext->pPrevious = pVictim->pPrevious;
}
/* adjust headpointer if necessary */
if(pVictim == pInterp->pCList)
{
pInterp->pCList = pVictim->pNext;
}
free(pVictim);
return 1;
}
#define MAXLEN 256
#define MAXCOM 50
extern char *stptok(char *s, char *tok, unsigned int toklen, char *brk);
extern char *SkipSpace(char *pPtr);
/*------------------------------------------------------------------------*/
int InterpExecute(SicsInterp *self,SConnection *pCon, char *pText)
{
int iCount = 0;
int iRet;
int i, argc;
char pBueffel[1024];
CommandList *pCommand = NULL;
char pBrk[] = {" \r\n\0"};
char *pPtr;
char **argv = NULL;
assert(self);
assert(pCon);
/* write info to Log */
if(pCon->pSock)
{
sprintf(pBueffel,"Executing -> %s <- from socket %d",pText,
pCon->pSock->sockid);
SICSLogWrite(pBueffel,eCommand);
}
else
{
printf("Executing -> %s <- from dummy socket\n", pText);
SICSLogWrite(pBueffel,eCommand);
}
/* convert to argc, argv */
argc = 0;
Text2Arg(pText,&argc,&argv);
/* the first one must be the target object. If not given an empty
command string was given which will be silently ignored */
if(argc < 1)
{
return 1;
}
if(argv[0] == NULL)
{
SCWrite(pCon,"ERROR: failed to parse command",eError);
return -1;
}
/* find it */
pCommand = FindCommand(self,argv[0]);
if(!pCommand)
{
sprintf(pBueffel,"ERROR: Object -> %s <- NOT found",
argv[0]);
SCWrite(pCon,pBueffel,eError);
return -1;
}
/* invoke the command */
self->eOut = eStatus;
Tcl_ResetResult((Tcl_Interp *)self->pTcl);
MacroPush(pCon);
iRet = pCommand->OFunc(pCon, self, pCommand->pData, argc, argv);
MacroPop();
/* delete argv */
for(i = 0; i < argc; i++)
{
if(argv[i] != NULL)
{
free(argv[i]);
}
}
free(argv);
return iRet;
}
/*------------------------------------------------------------------------*/
CommandList *FindCommand(SicsInterp *self, char *pName)
{
CommandList *pCurrent = NULL;
char pBueffel[256], *pCmd;
assert(self);
if(self->iDeleting)
{
return NULL;
}
strcpy(pBueffel,pName);
strtolower(pBueffel);
pCmd=TranslateAlias(&self->AList, pBueffel); /* M.Z. */
pCurrent = self->pCList;
while(pCurrent)
{
if(pCurrent->pName != NULL)
{
if(strcmp(pCurrent->pName, pCmd) == 0 ) /* M.Z. */
{
return pCurrent;
}
}
pCurrent = pCurrent->pNext;
}
return NULL;
}
/*------------------------------------------------------------------------*/
int WriteSicsStatus(SicsInterp *self, char *file, int iMot)
{
CommandList *pCurrent = NULL;
FILE *fd = NULL;
Dummy *pDum = NULL;
float fVal;
pIDrivable pDriv = NULL;
void *pTest = NULL;
assert(self);
assert(file);
/* open file */
fd = fopen(file,"w");
if(!fd)
{
return 0;
}
/* remove it, as I found garbage from previous runs in the
status file
*/
fclose(fd);
remove(file);
fd = fopen(file,"w");
if(!fd)
{
return 0;
}
/* cycle through the list */
pCurrent = self->pCList;
while(pCurrent)
{
pDum = (Dummy *)pCurrent->pData;
if(pDum)
{
pDum->pDescriptor->SaveStatus(pCurrent->pData,pCurrent->pName,fd);
if(iMot)
{
/*
save values of motors but not of environment devices as they
may not be present the next time round
*/
pDriv = pDum->pDescriptor->GetInterface(pDum,DRIVEID);
pTest = pDum->pDescriptor->GetInterface(pDum,ENVIRINTERFACE);
if(pDriv && !pTest)
{
if(strcmp(pDum->pDescriptor->name,"Motor") == 0)
{
MotorGetSoftPosition((pMotor)pDum,pServ->dummyCon,&fVal);
}
else
{
fVal = pDriv->GetValue(pDum,pServ->dummyCon);
}
if(fVal > -990.)
{
fprintf(fd,"run %s %f\n",pCurrent->pName, fVal);
}
}
}
}
pCurrent = pCurrent->pNext;
}
if(iMot)
{
fprintf(fd,"Success \n");
}
fclose(fd);
return 1;
}
/*------------------------------------------------------------------------*/
void DeleteInterp(SicsInterp *self)
{
CommandList *pCurrent = NULL;
CommandList *pTemp;
Tcl_Interp *pTcl = NULL;
int i;
assert(self);
self->iDeleting = 1;
/* delete Commandlist */
pCurrent = self->pCList;
while(pCurrent)
{
if(pCurrent->KFunc)
{
pCurrent->KFunc(pCurrent->pData);
}
if(pCurrent->pName)
{
/* printf("Deleting %s\n",pCurrent->pName); */
free(pCurrent->pName);
}
pTemp = pCurrent->pNext;
free(pCurrent);
pCurrent = pTemp;
}
FreeAliasList(&self->AList); /* M.Z. */
/* clear Tcl_Interpreter. Must be AFTER deleting command list because
some devices may have Tcl drivers which need to be accessed for
proper closing of devices.
*/
pTcl = (Tcl_Interp *)self->pTcl;
if(pTcl)
{
Tcl_DeleteInterp(pTcl);
}
free(self);
}
/*--------------------------------------------------------------------------*/
int ListObjects(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
CommandList *pCurrent;
char pBueffel[256];
int iNum = 0;
assert(pSics);
assert(pCon);
pCurrent = pSics->pCList;
while(pCurrent)
{
if(iNum == 0)
{
strcpy(pBueffel,pCurrent->pName);
iNum++;
}
else if(iNum < 4)
{
strcat(pBueffel," ");
strcat(pBueffel,pCurrent->pName);
iNum++;
}
else
{
strcat(pBueffel," ");
strcat(pBueffel,pCurrent->pName);
strcat(pBueffel,"\r\n");
SCWrite(pCon,pBueffel,eStatus);
iNum = 0;
}
pCurrent = pCurrent->pNext;
}
/* write final entries */
if(strlen(pBueffel) > 2)
{
strcat(pBueffel,"\r\n");
SCWrite(pCon,pBueffel,eStatus);
}
return 1;
}
/*---------------------------------------------------------------------------*/
int InterpWrite(SicsInterp *pSics, char *buffer)
{
Tcl_Interp *pTcl = NULL;
assert(pSics);
pTcl = (Tcl_Interp *)pSics->pTcl;
Tcl_SetResult(pTcl,buffer,TCL_VOLATILE);
return 1;
}
/*---------------------------------------------------------------------------*/
Tcl_Interp *InterpGetTcl(SicsInterp *pSics)
{
Tcl_Interp *pTcl = NULL;
pTcl = (Tcl_Interp *)pSics->pTcl;
return pTcl;
}
/*---------------------------------------------------------------------------*/
void strtolower(char *pText)
{
assert(pText);
while(*pText != '\0')
{
*pText = tolower(*pText);
pText++;
}
}
/*---------------------------------------------------------------------------*/
void argtolower(int argc, char *argv[])
{
int i;
for(i = 0; i < argc; i++)
{
strtolower(argv[i]);
}
}
/*------------------------------------------------------------------------*/
char *FindAlias(SicsInterp *self, void *pData)
{
CommandList *pCurrent = NULL;
assert(self);
if(self->iDeleting)
{
return NULL;
}
pCurrent = self->pCList;
while(pCurrent)
{
if(pCurrent->pData == pData)
{
return pCurrent->pName;
}
pCurrent = pCurrent->pNext;
}
return NULL;
}
/*---------------------------------------------------------------------------*/
void *FindCommandData(SicsInterp *pSics, char *name, char *cclass)
{
CommandList *pCom;
pDummy pDum = NULL;
pCom = FindCommand(pSics,name);
if(!pCom)
{
return NULL;
}
if(!pCom->pData)
return NULL;
pDum = (pDummy)pCom->pData;
if(strcmp(pDum->pDescriptor->name,cclass) == 0)
{
return pCom->pData;
}
return NULL;
}
/*------------------------------------------------------------------------*/
void *FindDrivable(SicsInterp *pSics, char *name){
pIDrivable pDriv;
pDummy pDum = NULL;
CommandList *pCom = NULL;
pCom = FindCommand(pSics,name);
if(pCom != NULL){
pDum = (pDummy)pCom->pData;
if(pDum != NULL){
return pDum->pDescriptor->GetInterface(pDum,DRIVEID);
}
}
return NULL;
}

151
SCinter.h Normal file
View File

@ -0,0 +1,151 @@
/*--------------------------------------------------------------------------
The SICS needs an interpreter. This is it.
Mark Koennecke, November 1996
copyright: see implementation file
---------------------------------------------------------------------------*/
#ifndef SICSINTERPRETER
#define SICSINTERPRETER
#include "Scommon.h"
#include <tcl.h>
/* M.Z. */
#include "definealias.i"
typedef struct __SConnection *pSConnection;
typedef struct __SINTER *pSicsInterp;
typedef int (*ObjectFunc)(pSConnection pCon, pSicsInterp pInter, void
*pData, int argc, char *argv[]);
typedef void (*KillFunc)(void *pData);
typedef struct __Clist {
char *pName;
ObjectFunc OFunc;
KillFunc KFunc;
void *pData;
struct __Clist *pNext;
struct __Clist *pPrevious;
} CommandList;
typedef struct __SINTER
{
CommandList *pCList;
OutCode eOut;
void *pTcl;
int iDeleting;
AliasList AList; /* M.Z. */
}SicsInterp;
/*-------------------------------------------------------------------------*/
SicsInterp *InitInterp(void);
/* makes a new interpreter. Returns him on success, else NULL
*/
/*------------------------------------------------------------------------*/
int AddCommand(SicsInterp *pInterp, char *pName, ObjectFunc pFunc,
KillFunc pKFunc, void *pData);
/* adds a new command, Returns True or False, depending on success
Parameters:
pInterp : the interpreter to add the command to.
pName : the commands name
pFunc : the object function to call when this command is
invoked. Definition of type: see above
pKFunc : function to call in order to delete command data.
type definition: above
pData : pointer to the command's own datastructure. Will be
passed as pData with each call to Ofunc.
*/
/*-------------------------------------------------------------------------*/
int RemoveCommand(SicsInterp *pInterp, char *pName);
/* kills the command name from the interpreter pInterp
*/
/*-------------------------------------------------------------------------*/
int InterpExecute(SicsInterp *self,pSConnection pCon,char *pCommand);
/*
executes a command in the interpreter self. Essentially converts
pCommand in an argc, argv[] pair, sets various status things and
invokes the object function. Takes care of status and error reporting
afterwards.
Parameters:
self : interpreter to invoke command in.
The connection pCon will be used for I/O and status reporting.
The command to invoke is the string pCommand.
Returns -1 if the command can not be found.
If the command is found, 1 is returned on success, 0 on failure in
the command.
----------------------------------------------------------------------------*/
CommandList *FindCommand(SicsInterp *pInterp, char *name);
/*
Searches the Interpreters pInterp command list for a command
with name. Returns ist datastructure if found, NULL else
*/
/*-------------------------------------------------------------------------*/
int WriteSicsStatus(SicsInterp *pSics,char *file, int iMot);
/*
SICS needs a way to save the status of each object into a file.
This is done by invoking for each object the object descriptor
function SaveStatus. This function does just that.
Parameters:
pSics : the interpreter to use.
file : the file to write the information to.
iMot : flag if motor position shall be saved or not
Returns: 1 on success, 0 on failure.
---------------------------------------------------------------------------*/
int InterpWrite(SicsInterp *pSics, char *buffer);
/*
writes result to Tcl, used for Macro mechanism.
This is an internal function and should not be used.
----------------------------------------------------------------------------*/
void DeleteInterp(SicsInterp *self);
/*
deletes the interpreter self aand clears all asoociated datastructures.
self will no longer be valid after this.
--------------------------------------------------------------------------- */
void strtolower(char *pText);
/*
strtolower converts a string to lowercase
--------------------------------------------------------------------------- */
void argtolower(int argc, char *argv[]);
/*
converts an argc, argv[] pair to lowercase
*/
/*--------------------------------------------------------------------------
FindAlias tries to find an alias to the datastructure given as second
parameter. Returns the command name on success, else NULL. Be warned, this
is very special
*/
char *FindAlias(SicsInterp *pSics, void *pData);
/*-------------------------------------------------------------------------
FindCommandData finds a command with the name given. It tests the name in the
ObjectDescriptor to be of name class. If all this succeeds a pointer
to the commands data structure is retuned. Else NULL
*/
void *FindCommandData(SicsInterp *pSics, char *name, char *comclass);
/*------------------------------------------------------------------------
FindDrivable tries to find Drivable object by the name given. Returns a
pointer to the drivable interface in the case of success, NULL in
case of failure. In order to save me fixing header files the pointer must
be cast to the drivable interface pointer.
------------------------------------------------------------------------*/
void *FindDrivable(SicsInterp *pics, char *name);
/*-----------------------------------------------------------------------
Get a copy of the Tcl interpreter
------------------------------------------------------------------------*/
Tcl_Interp *InterpGetTcl(SicsInterp *pSics);
#endif

87
SICSmain.c Normal file
View File

@ -0,0 +1,87 @@
/*--------------------------------------------------------------------------
THE SICS SERVER
This file contains the main entry point into the world of SICS.
Mark Koennecke, October 1996
Copyright: see copyright.h
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "nserver.h"
/***************************** Necessary Globals ****************************/
IPair *pSICSOptions = NULL;
pServer pServ = NULL;
/* ========================= Less dreadful file statics =================== */
#define DEFAULTINIFILE "servo.tcl"
/*---------------------------------------------------------------------------
The Servers Main program. May take one argument: the name of an
initialisation file
*/
int main(int argc, char *argv[])
{
int iRet;
/* initialise, will die on you if problems */
if(argc >= 2)
{
iRet = InitServer(argv[1],&pServ);
}
else
{
iRet = InitServer(NULL,&pServ);
}
if(!iRet)
{
printf("Unrecoverable error on server startup, exiting.........");
exit(1);
}
RunServer(pServ);
StopServer(pServ);
pServ = NULL;
exit(0);
}
/*--------------------------------------------------------------------------*/
SicsInterp *GetInterpreter(void)
{
return pServ->pSics;
}
/*--------------------------------------------------------------------------*/
pExeList GetExecutor(void)
{
return pServ->pExecutor;
}
/*------------------------------------------------------------------------*/
void StopExit(void)
{
if(pServ)
{
StopServer(pServ);
}
}
/*-------------------------------------------------------------------------*/
pTaskMan GetTasker(void)
{
return pServ->pTasker;
}

82
Scommon.h Normal file
View File

@ -0,0 +1,82 @@
/*-------------------------------------------------------------------------
Some common types and functions for SICS
Mark Koennecke, October 1996
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#ifndef SICSCOMMON
#define SICSCOMMON
/* this enum defines the output types in SICS */
typedef enum {
eInternal,
eCommand,
eHWError,
eInError,
eStatus,
eValue,
eWarning,
eError
} OutCode;
#include "interrupt.h"
/* define some user rights codes */
#define usInternal 0
#define usMugger 1
#define usUser 2
#define usSpy 3
/* status and error codes */
#define OKOK 1
#define HWIdle 2
#define HWBusy 3
#define HWFault 4
#define HWPosFault 5
#define HWCrash 6
#define NOMEMORY 7
#define HWNoBeam 8
#define HWPause 9
#define HWWarn 10
#define HWRedo 11
/*
Sics uses some server options for some server configuration parameters.
These options are held in the global variable pSICSOptions.
*/
#include "ifile.h"
extern IPair *pSICSOptions;
#endif

16
access.c Normal file
View File

@ -0,0 +1,16 @@
/* ------------------------------------------------------------------------
The Accesscode names for SICS
Mark Koennecke, November 1996
----------------------------------------------------------------------------*/
#ifndef PCODE
#define PCODE
static char *aCode[] = {
"internal",
"mugger",
"user",
"spy",
NULL };
static int iCodes = 4;
#endif

214
alias.c Normal file
View File

@ -0,0 +1,214 @@
/*-----------------------------------------------------------------------
A L I A S
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
First Version: 1998, Mark Koennecke
updated: November 1999, Mark Koennecke
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <tcl.h>
#include <assert.h>
#include "fortify.h"
#include "sics.h"
#include "splitter.h"
#include "alias.h"
/*
Usage: SicsAlias object newname
*/
int SicsAlias(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
CommandList *pCom = NULL;
char pBueffel[256];
int iRet;
if(!SCMatchRights(pCon,usMugger))
{
SCWrite(pCon,"ERROR: aliasing only allowed to Managers",
eError);
return 0;
}
if(argc < 3)
{
SCWrite(pCon,"ERROR: insufficient number of arguments to SicsAlias",
eError);
return 0;
}
argtolower(argc,argv);
/* first parameter should be an registered SICS object */
pCom = FindCommand(pSics,argv[1]);
if(!pCom)
{
sprintf(pBueffel,"ERROR: cannot find %s, no alias created",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* alright: create the alias */
iRet = AddCommand(pSics,argv[2],pCom->OFunc,NULL,pCom->pData);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
return 1;
}
/*--------------------------------------------------------------------
Make Alias: a command which installs a general alias into SICS.
*/
typedef struct {
pObjectDescriptor pDes;
char *pCommand;
}Alias, *pAlias;
/*----------------------------------------------------------------------*/
static void FreeAlias(void *pData)
{
pAlias self = (pAlias)pData;
if(!self)
return;
if(self->pDes)
DeleteDescriptor(self->pDes);
if(self->pCommand)
free(self->pCommand);
free(self);
}
/*----------------------------------------------------------------------
In order to make alias most general alias tries to find the interfaces
defined by the object corresponding to the first word in the command.
Note: does not work, the object pointer with which a interface function
will be called refers to the alias and not the proper thing: core dump!
Therefore disabled!
*/
static void *AliasInterface(void *pData, int iID)
{
CommandList *pCom = NULL;
pDummy pDum = NULL;
char *pPtr = NULL;
pAlias self = (pAlias)pData;
assert(self);
pPtr = strtok(self->pCommand," \t\n");
pCom = FindCommand(pServ->pSics,pPtr);
if(!pCom)
return NULL;
pDum = (pDummy)pCom->pData;
if(!pDum)
return NULL;
return pDum->pDescriptor->GetInterface(pDum,iID);
}
/*-----------------------------------------------------------------------*/
static int AliasAction(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[])
{
pAlias self = NULL;
int status;
char pLine[512];
char *pPtr;
Tcl_DString command;
self = (pAlias)pData;
assert(self);
/*
build command by appending the alias command and any possible
arguments given.
*/
Tcl_DStringInit(&command);
Tcl_DStringAppend(&command, self->pCommand,-1);
Tcl_DStringAppend(&command," ",-1);
Arg2Text(argc-1,&argv[1],pLine,511);
Tcl_DStringAppend(&command,pLine,-1);
/* execute the command on the current connection */
status = SCInvoke(pCon,pSics,Tcl_DStringValue(&command));
/* finish */
Tcl_DStringFree(&command);
return status;
}
/*-----------------------------------------------------------------------*/
int MakeAlias(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
char pBueffel[512];
int iRet;
pAlias pNew = NULL;
if(argc < 3)
{
SCWrite(pCon,"ERROR: insufficient number of arguments to alias",
eError);
return 0;
}
Arg2Text(argc-2,&argv[2],pBueffel,511);
/* create data structure */
pNew = (pAlias)malloc(sizeof(Alias));
if(!pNew)
{
SCWrite(pCon,"ERROR: out of memory while creating alias",eError);
return 0;
}
pNew->pDes = CreateDescriptor("Alias");
pNew->pCommand = strdup(pBueffel);
if( !pNew->pDes || !pNew->pCommand)
{
SCWrite(pCon,"ERROR: out of memory while creating alias",eError);
return 0;
}
iRet = AddCommand(pSics,
argv[1],
AliasAction,
FreeAlias,
pNew);
if(!iRet)
{
FreeAlias(pNew);
SCWrite(pCon,"ERROR: duplicate object name NOT created",eError);
return 0;
}
return 1;
}

20
alias.h Normal file
View File

@ -0,0 +1,20 @@
/*------------------------------------------------------------------------
A L I A S
Implementation of the alias command. This is a configuration command
which allows additional names "aliases" for an existing object.
Mark Koennecke, March 1997
copyright: see implementation file
-------------------------------------------------------------------------*/
#ifndef SICSALIAS
#define SICSALIAS
int SicsAlias(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int MakeAlias(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif

245
amor.dic Normal file
View File

@ -0,0 +1,245 @@
##NXDICT-1.0
#----------------------------------------------------------------------------
# NeXus dictionary file for the SINQ instrument AMOR
#
# DO NOT EDIT WHEN YOU DO NOT KNOW WHAT YOU ARE DOING!
# This file determines the placement of data items in the AMOR NeXus
# data file. Your data may not be readable if this file is messed up.
#
# Mark Koennecke, September 1999
#----------------------------------------------------------------------------
# AMOR may have variable time binning. In order
# to cope with that, we use NXDICT's text replacement feature and define
# these things
timebin=512
detxsize=255
detysize=128
scanlength = 10
chunk =
#---------- NXentry level
etitle=/entry1,NXentry/SDS title -type DFNT_CHAR -rank 1 -dim {132}
estart=/entry1,NXentry/SDS start_time -type DFNT_CHAR -rank 1 -dim {132}
eend=/entry1,NXentry/SDS end_time -type DFNT_CHAR -rank 1 -dim {132}
#----------------- NXinstrument
iname=/entry1,NXentry/reflectometer,NXinstrument/SDS name -type DFNT_CHAR \
-rank 1 -dim {132}
#----------------- NXsource
sname=/entry1,NXentry/reflectometer,NXinstrument/SINQ,NXsource/SDS name \
-type DFNT_CHAR -rank 1 -dim {132}
stype=/entry1,NXentry/reflectometer,NXinstrument/SINQ,NXsource/SDS type \
-type DFNT_CHAR -rank 1 -dim {132}
#----------------- Chopper
cname=/entry1,NXentry/reflectometer,NXinstrument/chopper,NXchopper/SDS name \
-type DFNT_CHAR -rank 1 -dim {132}
crot=/entry1,NXentry/reflectometer,NXinstrument/chopper,NXchopper/SDS \
rotation_speed -attr {units,rpm}
#---------------- frame overlap mirror
fomname=/entry1,NXentry/reflectometer,NXinstrument/frame_overlap_mirror,NXfilter/SDS name \
-type DFNT_CHAR -rank 1 -dim {132}
fomh=/entry1,NXentry/reflectometer,NXinstrument/frame_overlap_mirror,NXfilter/SDS \
omega_height -attr {units,mm}
fomom=/entry1,NXentry/reflectometer,NXinstrument/frame_overlap_mirror,NXfilter/SDS \
omega -attr {units,degree}
fodist=/entry1,NXentry/reflectometer,NXinstrument/frame_overlap_mirror,NXfilter/SDS \
distance -attr {units,mm}
#-------------- first slit
d1l=/entry1,NXentry/reflectometer,NXinstrument/diaphragm1,NXfilter/SDS left \
-attr {units,mm}
d1r=/entry1,NXentry/reflectometer,NXinstrument/diaphragm1,NXfilter/SDS right \
-attr {units,mm}
d1t=/entry1,NXentry/reflectometer,NXinstrument/diaphragm1,NXfilter/SDS top \
-attr {units,mm}
d1b=/entry1,NXentry/reflectometer,NXinstrument/diaphragm1,NXfilter/SDS bottom \
-attr {units,mm}
d1dist=/entry1,NXentry/reflectometer,NXinstrument/diaphragm1,NXfilter/SDS distance \
-attr {units,mm}
#---------- polarizing mirror
polname=/entry1,NXentry/reflectometer,NXinstrument/polarizer,NXfilter/SDS name \
-type DFNT_CHAR -rank 1 -dim {132}
polz=/entry1,NXentry/reflectometer,NXinstrument/polarizer,NXfilter/SDS height \
-attr {units,mm}
polzom=/entry1,NXentry/reflectometer,NXinstrument/polarizer,NXfilter/SDS omega_height \
-attr {units,mm}
polom=/entry1,NXentry/reflectometer,NXinstrument/polarizer,NXfilter/SDS omega \
-attr {units,degree}
poly=/entry1,NXentry/reflectometer,NXinstrument/polarizer,NXfilter/SDS y_position \
-attr {units,mm}
poldist=/entry1,NXentry/reflectometer,NXinstrument/polarizer,NXfilter/SDS distance \
-attr {units,mm}
#-------------- second slit
d2l=/entry1,NXentry/reflectometer,NXinstrument/diaphragm2,NXfilter/SDS left \
-attr {units,mm}
d2r=/entry1,NXentry/reflectometer,NXinstrument/diaphragm2,NXfilter/SDS right \
-attr {units,mm}
d2t=/entry1,NXentry/reflectometer,NXinstrument/diaphragm2,NXfilter/SDS top \
-attr {units,mm}
d2b=/entry1,NXentry/reflectometer,NXinstrument/diaphragm2,NXfilter/SDS bottom \
-attr {units,mm}
d2dist=/entry1,NXentry/reflectometer,NXinstrument/diaphragm2,NXfilter/SDS distance \
-attr {units,mm}
#-------------- third slit
d3l=/entry1,NXentry/reflectometer,NXinstrument/diaphragm3,NXfilter/SDS left \
-attr {units,mm}
d3r=/entry1,NXentry/reflectometer,NXinstrument/diaphragm3,NXfilter/SDS right \
-attr {units,mm}
d3t=/entry1,NXentry/reflectometer,NXinstrument/diaphragm3,NXfilter/SDS top \
-attr {units,mm}
d3b=/entry1,NXentry/reflectometer,NXinstrument/diaphragm3,NXfilter/SDS bottom \
-attr {units,mm}
d3dist=/entry1,NXentry/reflectometer,NXinstrument/diaphragm3,NXfilter/SDS distance \
-attr {units,mm}
#---------------- sample table
saname=/entry1,NXentry/sample,NXsample/SDS name \
-type DFNT_CHAR -rank 1 -dim {132}
baseheight=/entry1,NXentry/sample,NXsample/SDS base_height \
-attr {units,mm}
somheight=/entry1,NXentry/sample,NXsample/SDS omega_height \
-attr {units,mm}
schi=/entry1,NXentry/sample,NXsample/SDS chi \
-attr {units,degree}
somega=/entry1,NXentry/sample,NXsample/SDS omega \
-attr {units,degree}
stheight=/entry1,NXentry/sample,NXsample/SDS table_height \
-attr {units,mm}
stdist=/entry1,NXentry/sample,NXsample/SDS distance \
-attr {units,mm}
#------------ fourth slit
d4l=/entry1,NXentry/reflectometer,NXinstrument/diaphragm4,NXfilter/SDS left \
-attr {units,mm}
d4r=/entry1,NXentry/reflectometer,NXinstrument/diaphragm4,NXfilter/SDS right \
-attr {units,mm}
d4t=/entry1,NXentry/reflectometer,NXinstrument/diaphragm4,NXfilter/SDS top \
-attr {units,mm}
d4b=/entry1,NXentry/reflectometer,NXinstrument/diaphragm4,NXfilter/SDS bottom \
-attr {units,mm}
d4dist=/entry1,NXentry/reflectometer,NXinstrument/diaphragm4,NXfilter/SDS \
distance_to_sample -attr {units,mm}
d4base =/entry1,NXentry/reflectometer,NXinstrument/diaphragm4,NXfilter/SDS \
base_height -attr {units,mm}
#------------ analyzer
anname=/entry1,NXentry/reflectometer,NXinstrument/polarizer,NXfilter/SDS name \
-type DFNT_CHAR -rank 1 -dim {132}
anoz=/entry1,NXentry/reflectometer,NXinstrument/analyzer,NXfilter/SDS omega_height \
-attr {units,mm}
abase=/entry1,NXentry/reflectometer,NXinstrument/analyzer,NXfilter/SDS base_height \
-attr {units,mm}
adis=/entry1,NXentry/reflectometer,NXinstrument/analyzer,NXfilter/SDS \
distance_to_sample -attr {units,mm}
anom=/entry1,NXentry/reflectometer,NXinstrument/analyzer,NXfilter/SDS omega \
-attr {units,degree}
antz=/entry1,NXentry/reflectometer,NXinstrument/analyzer,NXfilter/SDS height \
-attr {units,mm}
andist=/entry1,NXentry/reflectometer,NXinstrument/analyzer,NXfilter/SDS distance \
-attr {units,mm}
#--------------- fifth slit!!
d5l=/entry1,NXentry/reflectometer,NXinstrument/diaphragm5,NXfilter/SDS left \
-attr {units,mm}
d5r=/entry1,NXentry/reflectometer,NXinstrument/diaphragm5,NXfilter/SDS right \
-attr {units,mm}
d5t=/entry1,NXentry/reflectometer,NXinstrument/diaphragm5,NXfilter/SDS top \
-attr {units,mm}
d5b=/entry1,NXentry/reflectometer,NXinstrument/diaphragm5,NXfilter/SDS bottom \
-attr {units,mm}
d5dist=/entry1,NXentry/reflectometer,NXinstrument/diaphragm5,NXfilter/SDS \
distance_to_sample -attr {units,mm}
d5base =/entry1,NXentry/reflectometer,NXinstrument/diaphragm5,NXfilter/SDS \
base_height -attr {units,mm}
#---------- count control
cnmode=/entry1,NXentry/reflectometer,NXinstrument/counter,NXmonitor/SDS count_mode \
-type DFNT_CHAR -rank 1 -dim {30}
cnpreset=/entry1,NXentry/reflectometer,NXinstrument/counter,NXmonitor/SDS preset \
-attr {units,countsOrseconds}
cntime=/entry1,NXentry/reflectometer,NXinstrument/counter,NXmonitor/SDS time \
-attr {units,seconds}
cnmon1=/entry1,NXentry/reflectometer,NXinstrument/counter,NXmonitor/SDS monitor1 \
-type DFNT_INT32 -attr {units,counts}
cnmon2=/entry1,NXentry/reflectometer,NXinstrument/counter,NXmonitor/SDS monitor2 \
-type DFNT_INT32 -attr {units,counts}
#-------------- detector-TOF mode
dettype=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS type \
-type DFNT_CHAR -rank 1 -dim {132}
dety=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS y_detector \
-type DFNT_FLOAT32 -rank 1 -dim {$(detysize)} -attr {axis,1} \
-attr {units,mm}
detxx=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS x_detector \
-type DFNT_FLOAT32 -rank 1 -dim {$(detxsize)} -attr {axis,2} \
-attr {units,mm}
detz=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS z \
-type DFNT_FLOAT32 -rank 1 -dim {$(detxsize)} -attr {axis,2} \
-attr {units,mm}
detx=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS x \
-type DFNT_FLOAT32 -attr {units,mm}
detom=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS omega \
-type DFNT_FLOAT32 -attr {units,degree}
detheight=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS height \
-type DFNT_FLOAT32 -attr {units,mm}
detdist=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS \
distance_to_sample -type DFNT_FLOAT32 -attr {units,mm}
detbase=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS \
base_height -type DFNT_FLOAT32 -attr {units,mm}
dettime=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS time_binning \
-type DFNT_FLOAT32 -rank 1 -dim {$(timebin)} -attr {axis,3} \
-attr {units,ms}
spinup=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS spinup \
-type DFNT_INT32 -rank 3 -dim {$(detxsize),$(detysize),$(timebin)} \
-LZW $(chunk) -attr {signal,1}
#spinup=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS spinup \
# -type DFNT_INT32 -rank 3 -dim {$(detxsize),$(detysize),$(timebin)} \
# $(chunk) -attr {signal,1}
detchunk=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS \
chunksize -type DFNT_INT32 -rank 1 -dim {3}
spinup2d=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS spinup \
-type DFNT_INT32 -rank 2 -dim {$(detxsize),$(detysize)} \
-LZW $(chunk) -attr {signal,1}
spindown=/entry1,NXentry/reflectometer,NXinstrument/TOF,NXdetector/SDS spindown \
-type DFNT_INT32 -rank 3 -dim {$(detxsize),$(detysize),$(timebin)} \
-LZW -attr {signal,1}
#------------ single detectors TOF -------------------------------------
singleup=/entry1,NXentry/reflectometer,NXinstrument/single,NXdetector/SDS \
spinup -type DFNT_INT32 -rank 2 -dim {2, $(timebin)} -LZW \
-attr {signal,1}
singledown=/entry1,NXentry/reflectometer,NXinstrument/single,NXdetector/SDS \
spinup -type DFNT_INT32 -rank 2 -dim {2, $(timebin)} -LZW \
-attr {signal,1}
singletime=/entry1,NXentry/reflectometer,NXinstrument/single,NXdetector/SDS \
time_binning -type DFNT_FLOAT32 -rank 1 -dim {$(timebin)} \
-attr {axis,2}
singletofmon=/entry1,NXentry/reflectometer,NXinstrument/single,NXdetector/SDS \
tof_monitor -type DFNT_INT32 -rank 1 -dim {$(timebin)}
#------------ detector: scan mode
scanroot=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS
sdetx=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS x \
-type DFNT_FLOAT32 -attr {units,mm}
sdetom=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS omega \
-type DFNT_FLOAT32 -attr {units,degree}
sdetheight=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS height \
-type DFNT_FLOAT32 -attr {units,mm}
spinupup=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS spinup_upper \
-type DFNT_INT32 -rank 1 -dim {$(scanlength)} -attr {signal,1}
spindownup=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS \
spindown_upper \
-type DFNT_INT32 -rank 1 -dim {$(scanlength)} -attr {signal,2}
spinuplo=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS spinup_lower \
-type DFNT_INT32 -rank 1 -dim {$(scanlength)} -attr {signal,3}
spindownlo=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS \
spindown_lower \
-type DFNT_INT32 -rank 1 -dim {$(scanlength)} -attr {signal,4}
somega=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS \
omega -attr {units,degree} \
-type DFNT_FLOAT32 -rank 1 -dim {$(scanlength)} -attr {axis,1}
smonitor1=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS \
monitor1 \
-type DFNT_INT32 -rank 1 -dim {$(scanlength)}
smonitor2=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS \
monitor2 \
-type DFNT_INT32 -rank 1 -dim {$(scanlength)}
stime=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS \
time \
-type DFNT_FLOAT32 -rank 1 -dim {$(scanlength)} -attr {units,s}
sdetdist=/entry1,NXentry/reflectometer,NXinstrument/scan,NXdetector/SDS distance \
-type DFNT_FLOAT32 -attr {units,mm}
#------------------- data vGroup
dana=/entry1,NXentry/TOF,NXdata/NXVGROUP
singledana=/entry1,NXentry/single,NXdata/NXVGROUP
sdana=/entry1,NXentry/scan,NXdata/NXVGROUP

996
amor2t.c Normal file
View File

@ -0,0 +1,996 @@
/*---------------------------------------------------------------------------
A M O R 2 T
A class for controlling the two theta movement of the reflectometer
AMOR at SINQ. It is not clear if this class may be useful for other
reflectometers, too. At AMOR the two theta movement of the detector is
realized by translating the detector along x and z. Also it can be
tilted in omega. Furthermore the height of two diaphragms has to be
adjusted when moving two theta as well. In polarizing mode the analyzer
mirror has to be moved as well.
copyright: see copyright.h
Mark Koennecke, September 1999
Bugs fixed, analyzer included for A2T. Then there is a second thing:
aoz2t which allows to scan the analyzer in two-theta during alignment
of the instrument. As all the parameters are already held in the a2t
structures this extra was added into this module.
Mark Koennecke, May-June 2000
---------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include "fortify.h"
#include <tcl.h>
#include "sics.h"
#include "motor.h"
#include "obpar.h"
#define DEBUG 1
#define MAXMOT 13
#define MAXPAR 13
#include "amor2t.i"
#include "amor2t.h"
/*
Defines for accessing various motors and variables. Definition of motor: see
annotated AMOR drawing.
*/
/* monochromator omega */
#define MOTMOM 0
/* sample omega */
#define MOTSOM 1
/* detector height movement */
#define MOTCOZ 2
/* detector movement along main axis */
#define MOTCOX 3
/* sample holder height movement */
#define MOTSTZ 4
/* whole sample table height movement */
#define MOTSOZ 5
/* lift for diaphragm 4*/
#define MOTD4B 6
/* lift for diaphragm 5 */
#define MOTD5B 7
/* detector omega movement */
#define MOTCOM 8
/* lift for analyzer */
#define MOTAOZ 9
/* analyzer omega */
#define MOTAOM 10
/* detector 2 movement */
#define MOTC3Z 11
/*======================================================================
The core of it all: The calculation of the settings for the various
motors.
========================================================================*/
static int CalculateAMORE(pAmor2T self, SConnection *pCon, float fNew)
{
float fMOM, fSOM, fSTZ, fSOZ, fAOM, fAOZ, fC3Z, fconstAOM;
double fAngle, fX, fZ, fZ2, fBase, fPIR;
float fCOZ, fCOX, fCOM;
int iRet;
#ifdef DEBUG
char pBueffel[132];
#endif
/* get the necessary angles first */
iRet = MotorGetSoftPosition(self->aEngine[MOTMOM],pCon,&fMOM);
if(iRet != 1)
{
return iRet;
}
iRet = MotorGetSoftPosition(self->aEngine[MOTSOM],pCon,&fSOM);
if(iRet != 1)
{
return iRet;
}
iRet = MotorGetSoftPosition(self->aEngine[MOTSTZ],pCon,&fSTZ);
if(iRet != 1)
{
return iRet;
}
iRet = MotorGetSoftPosition(self->aEngine[MOTSOZ],pCon,&fSOZ);
if(iRet != 1)
{
return iRet;
}
/* calculate base height of sample table */
fBase = fSOZ + ObVal(self->aParameter,PARDH);
fPIR = 180. / 3.1415926;
/* calculation for detector */
fAngle = fNew - 2*fMOM;
if(fAngle < 0)
{
fAngle = fAngle + 360.;
}
fAngle /= fPIR;
fX = ObVal(self->aParameter,PARDS)*cos(fAngle);
fZ = ObVal(self->aParameter,PARDS)*sin(fAngle);
self->toStart[0].pMot = self->aEngine[MOTCOX];
strcpy(self->toStart[0].pName,self->aEngine[MOTCOX]->name);
self->toStart[0].fTarget = fX - ObVal(self->aParameter,PARDS);
self->toStart[1].pMot = self->aEngine[MOTCOZ];
strcpy(self->toStart[1].pName,self->aEngine[MOTCOZ]->name);
self->toStart[1].fTarget = fZ + fBase -
ObVal(self->aParameter,PARDDH);
self->toStart[2].pMot = self->aEngine[MOTCOM];
strcpy(self->toStart[2].pName,self->aEngine[MOTCOM]->name);
self->toStart[2].fTarget = fNew - 2*fMOM;
self->iStart = 3;
/* calculation for diaphragm 4 */
fZ = ObVal(self->aParameter,PARDD4) * sin(fAngle);
self->toStart[3].pMot = self->aEngine[MOTD4B];
strcpy(self->toStart[3].pName,self->aEngine[MOTD4B]->name);
self->toStart[3].fTarget = fBase + fZ -
ObVal(self->aParameter,PARD4H);
self->iStart = 4;
/* calculation for diaphragm 5 */
fZ = ObVal(self->aParameter,PARDD5) * sin(fAngle);
self->toStart[4].pMot = self->aEngine[MOTD5B];
strcpy(self->toStart[4].pName,self->aEngine[MOTD5B]->name);
self->toStart[4].fTarget = fBase + fZ -
ObVal(self->aParameter,PARD5H);
self->iStart = 5;
#ifdef DEBUG
sprintf(pBueffel,"2T COZ COX COM D4B D5B ");
SCWrite(pCon,pBueffel,eValue);
sprintf(pBueffel,"%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f",
fNew, self->toStart[1].fTarget, self->toStart[0].fTarget,
self->toStart[2].fTarget, self->toStart[3].fTarget,
self->toStart[4].fTarget);
SCWrite(pCon,pBueffel,eValue);
#endif
if(ObVal(self->aParameter,ANAFLAG) > 0)
{
/* the analyzer height */
fZ = ObVal(self->aParameter,PARADIS)*sin(fAngle);
fAOZ = fBase + fZ - ObVal(self->aParameter,PARANA);
self->toStart[5].pMot = self->aEngine[MOTAOZ];
strcpy(self->toStart[5].pName,self->aEngine[MOTAOZ]->name);
self->toStart[5].fTarget = fAOZ;
self->iStart = 6;
/* analyzer omega */
self->toStart[6].pMot = self->aEngine[MOTAOM];
strcpy(self->toStart[6].pName,self->aEngine[MOTAOM]->name);
self->toStart[6].fTarget = fNew/2.
+ ObVal(self->aParameter,PARAOM);
self->iStart = 7;
/* C3Z */
fZ2 = (ObVal(self->aParameter,PARDS) - ObVal(self->aParameter,
PARADIS))*sin(fAngle + (fNew/fPIR) );
self->toStart[7].pMot = self->aEngine[MOTC3Z];
strcpy(self->toStart[7].pName,self->aEngine[MOTC3Z]->name);
self->toStart[7].fTarget = fBase + fZ + fZ2 -
ObVal(self->aParameter,PARDDD) -
self->toStart[1].fTarget;
self->iStart = 8;
#ifdef DEBUG
sprintf(pBueffel,"2T AOZ AOM C3Z");
SCWrite(pCon,pBueffel,eValue);
sprintf(pBueffel,"%6.2f %6.2f %6.2f %6.2f",
fNew, self->toStart[5].fTarget, self->toStart[6].fTarget,
self->toStart[7].fTarget);
SCWrite(pCon,pBueffel,eValue);
#endif
}
return 1;
}
/*=======================================================================
Calculations for Analyzer two theta
=========================================================================*/
static int CalculateANA2T(pAmor2T self, SConnection *pCon, float fNew)
{
double fBase, fPIR;
float fAOZ, fIncident, fSOM, fMOM, fDiffracted, fDistance, fX, fZ;
int iRet;
#ifdef DEBUG
char pBueffel[132];
#endif
/* calculate base height of analyzer table */
iRet = MotorGetSoftPosition(self->aEngine[MOTSOZ],pCon,&fAOZ);
if(iRet != 1)
{
return iRet;
}
fBase = fAOZ + ObVal(self->aParameter,PARANA);
fPIR = 180. / 3.1415926;
/* Calculate the incident angle at the analyzer */
iRet = MotorGetSoftPosition(self->aEngine[MOTSOM],pCon,&fSOM);
if(iRet != 1)
{
return iRet;
}
iRet = MotorGetSoftPosition(self->aEngine[MOTMOM],pCon,&fMOM);
if(iRet != 1)
{
return iRet;
}
fIncident = fMOM + 2. * fSOM;
/* calculate the angle of the diffracted beam against the
horizon at the analyzer.
fDiffracted = fIncident - 2. * AOM.
There is a problem here. We should read AOM in order to get the
value. However in the context of an omega - two-theta scan on AOM
and ana2t, it is fNew.
*/
fDiffracted = fIncident - fNew;
/* calculation for detector */
fDiffracted /= fPIR;
fDistance = ObVal(self->aParameter,PARDS) -
ObVal(self->aParameter, PARANA);
fX = fDistance*cos(fDiffracted);
fZ = fDistance*sin(fDiffracted);
self->toStart[0].pMot = self->aEngine[MOTCOX];
strcpy(self->toStart[0].pName,self->aEngine[MOTCOX]->name);
self->toStart[0].fTarget = fX - fDistance;
self->toStart[1].pMot = self->aEngine[MOTCOZ];
strcpy(self->toStart[1].pName,self->aEngine[MOTCOZ]->name);
self->toStart[1].fTarget = fZ + fBase -
ObVal(self->aParameter,PARDDH);
self->toStart[2].pMot = self->aEngine[MOTCOM];
strcpy(self->toStart[2].pName,self->aEngine[MOTCOM]->name);
self->toStart[2].fTarget = -fDiffracted*fPIR;
self->iStart = 3;
/* calculation for diaphragm 5 */
fZ = ObVal(self->aParameter,PARDD5) * sin(fDiffracted);
self->toStart[3].pMot = self->aEngine[MOTD5B];
strcpy(self->toStart[3].pName,self->aEngine[MOTD5B]->name);
self->toStart[3].fTarget = fBase + fZ -
ObVal(self->aParameter,PARD5H);
self->iStart = 4;
#ifdef DEBUG
sprintf(pBueffel,"2T COX COZ COM D5B ");
SCWrite(pCon,pBueffel,eValue);
sprintf(pBueffel,"%6.2f %6.2f %6.2f %6.2f %6.2f ",
fNew, self->toStart[0].fTarget, self->toStart[1].fTarget,
self->toStart[2].fTarget,self->toStart[3].fTarget);
SCWrite(pCon,pBueffel,eValue);
#endif
return 1;
}
/*========================================================================
Definition of interface functions.
=========================================================================*/
static long A2TSetValue(void *pData, SConnection *pCon, float fNew)
{
int i, iRet;
pIDrivable pDriv = NULL;
pAmor2T self = (pAmor2T) pData;
assert(self);
/* calculation */
iRet = CalculateAMORE(self,pCon,fNew);
if(iRet != 1)
{
return iRet;
}
/* start them all */
for(i = 0; i < self->iStart; i++)
{
pDriv = self->toStart[i].pMot->pDescriptor->GetInterface(
self->toStart[i].pMot,DRIVEID);
if(pDriv != NULL)
{
iRet = pDriv->SetValue(self->toStart[i].pMot,pCon,
self->toStart[i].fTarget);
if(iRet != OKOK)
{
return iRet;
}
}
}
return OKOK;
}
/*--------------------------------------------------------------------*/
static long ANA2TSetValue(void *pData, SConnection *pCon, float fNew)
{
int i, iRet;
pIDrivable pDriv = NULL;
pAmor2T self = (pAmor2T) pData;
assert(self);
/* calculation */
iRet = CalculateANA2T(self,pCon,fNew);
if(iRet != 1)
{
return iRet;
}
/* start them all */
for(i = 0; i < self->iStart; i++)
{
pDriv = self->toStart[i].pMot->pDescriptor->GetInterface(
self->toStart[i].pMot,DRIVEID);
if(pDriv != NULL)
{
iRet = pDriv->SetValue(self->toStart[i].pMot,pCon,
self->toStart[i].fTarget);
if(iRet != OKOK)
{
return iRet;
}
}
}
return OKOK;
}
/*-------------------------------------------------------------------------*/
static int A2THalt(void *pData)
{
int i, iRet;
pIDrivable pDriv = NULL;
pAmor2T self = (pAmor2T) pData;
assert(self);
/* stop them all */
for(i = 0; i < self->iStart; i++)
{
pDriv = self->toStart[i].pMot->pDescriptor->GetInterface(
self->toStart[i].pMot,DRIVEID);
if(pDriv != NULL)
{
iRet = pDriv->Halt(self->toStart[i].pMot);
}
}
return OKOK;
}
/*-----------------------------------------------------------------------*/
static int A2TCheck(void *pData, float fNew, char *error, int iErrLen)
{
int i, iRet;
pIDrivable pDriv = NULL;
pAmor2T self = (pAmor2T) pData;
SConnection *pDumCon = NULL;
assert(self);
pDumCon = SCCreateDummyConnection(pServ->pSics);
assert(pDumCon);
/* calculation */
iRet = CalculateAMORE(self,pDumCon,fNew);
SCDeleteConnection(pDumCon);
if(iRet != 1)
{
return iRet;
}
/* check them all */
for(i = 0; i < self->iStart; i++)
{
pDriv = self->toStart[i].pMot->pDescriptor->GetInterface(
self->toStart[i].pMot,DRIVEID);
if(pDriv != NULL)
{
iRet = pDriv->CheckLimits(self->toStart[i].pMot,
self->toStart[i].fTarget,
error,iErrLen);
if(iRet != 1)
{
return iRet;
}
}
}
return 1;
}
/*-------------------------------------------------------------------*/
static int ANA2TCheck(void *pData, float fNew, char *error, int iErrLen)
{
int i, iRet;
pIDrivable pDriv = NULL;
pAmor2T self = (pAmor2T) pData;
SConnection *pDumCon = NULL;
assert(self);
pDumCon = SCCreateDummyConnection(pServ->pSics);
assert(pDumCon);
/* calculation */
iRet = CalculateANA2T(self,pDumCon,fNew);
SCDeleteConnection(pDumCon);
if(iRet != 1)
{
return iRet;
}
/* check them all */
for(i = 0; i < self->iStart; i++)
{
pDriv = self->toStart[i].pMot->pDescriptor->GetInterface(
self->toStart[i].pMot,DRIVEID);
if(pDriv != NULL)
{
iRet = pDriv->CheckLimits(self->toStart[i].pMot,
self->toStart[i].fTarget,
error,iErrLen);
if(iRet != 1)
{
return iRet;
}
}
}
return 1;
}
/*------------------------------------------------------------------------*/
static int A2TStatus(void *pData, SConnection *pCon)
{
int i, iRet;
pIDrivable pDriv = NULL;
pAmor2T self = (pAmor2T) pData;
assert(self);
/* check them all */
for(i = 0; i < self->iStart; i++)
{
pDriv = self->toStart[i].pMot->pDescriptor->GetInterface(
self->toStart[i].pMot,DRIVEID);
if(pDriv != NULL)
{
iRet = pDriv->CheckStatus(self->toStart[i].pMot,pCon);
if( (iRet != OKOK) && (iRet != HWIdle) )
{
return iRet;
}
}
}
return iRet;
}
/*------------------------------------------------------------------------*/
static float A2TGetValue(void *pData, SConnection *pCon)
{
float fVal, fMOM, fResult;
int iRet;
pAmor2T self = (pAmor2T) pData;
assert(self);
/* get COM */
iRet = MotorGetSoftPosition(self->aEngine[MOTCOM], pCon, &fVal);
if(!iRet)
{
return -9999.99;
}
/* get MOM */
iRet = MotorGetSoftPosition(self->aEngine[MOTMOM], pCon, &fMOM);
if(!iRet)
{
return -9999.99;
}
/* retrocalculate 2 theta */
fResult = fVal + 2*fMOM;
return fResult;
}
/*------------------------------------------------------------------------*/
static float ANA2TGetValue(void *pData, SConnection *pCon)
{
float fVal, fMOM, fResult;
int iRet;
pAmor2T self = (pAmor2T) pData;
assert(self);
/* get AOM */
iRet = MotorGetSoftPosition(self->aEngine[MOTAOM], pCon, &fVal);
if(!iRet)
{
return -9999.99;
}
return 2. * fVal;
}
/*-----------------------------------------------------------------------*/
static void *A2TGetInterface(void *pData, int iID)
{
pAmor2T self = (pAmor2T) pData;
assert(self);
if(iID == DRIVEID)
{
return self->pDriv;
}
return NULL;
}
/*------------------------------------------------------------------------*/
static int A2TSave(void *pData, char *name, FILE *fd)
{
int i;
pAmor2T self = (pAmor2T) pData;
assert(self);
fprintf(fd,"%s detectord %f \n", name, ObVal(self->aParameter,PARDS));
fprintf(fd,"%s sampleh %f \n", name, ObVal(self->aParameter,PARDH));
fprintf(fd,"%s d4d %f \n", name, ObVal(self->aParameter,PARDD4));
fprintf(fd,"%s d5d %f \n", name, ObVal(self->aParameter,PARDD5));
fprintf(fd,"%s interrupt %f \n", name, ObVal(self->aParameter,PARINT));
fprintf(fd,"%s detectorh %f \n", name, ObVal(self->aParameter,PARDDH));
fprintf(fd,"%s d4h %f \n", name, ObVal(self->aParameter,PARD4H));
fprintf(fd,"%s d5h %f \n", name, ObVal(self->aParameter,PARD5H));
fprintf(fd,"%s anah %f \n", name, ObVal(self->aParameter,PARANA));
fprintf(fd,"%s anad %f \n", name, ObVal(self->aParameter,PARADIS));
fprintf(fd,"%s anaflag %f \n", name, ObVal(self->aParameter,ANAFLAG));
fprintf(fd,"%s c2h %f \n", name, ObVal(self->aParameter,PARDDD));
fprintf(fd,"%s aomconst %f \n", name, ObVal(self->aParameter,PARAOM));
return 1;
}
/*------------------------------------------------------------------------*/
static void A2TList(pAmor2T self, SConnection *pCon, char *name)
{
char pBueffel[132];
Tcl_DString tString;
assert(pCon);
assert(self);
Tcl_DStringInit(&tString);
sprintf(pBueffel,
"%s.detectord %f \n", name, ObVal(self->aParameter,PARDS));
Tcl_DStringAppend(&tString,pBueffel,-1);
sprintf(pBueffel,
"%s.sampleh %f \n", name, ObVal(self->aParameter,PARDH));
Tcl_DStringAppend(&tString,pBueffel,-1);
sprintf(pBueffel,
"%s.d4d %f \n", name, ObVal(self->aParameter,PARDD4));
Tcl_DStringAppend(&tString,pBueffel,-1);
sprintf(pBueffel,
"%s.d5d %f \n", name, ObVal(self->aParameter,PARDD5));
Tcl_DStringAppend(&tString,pBueffel,-1);
sprintf(pBueffel,
"%s.interrupt %f \n", name, ObVal(self->aParameter,PARINT));
Tcl_DStringAppend(&tString,pBueffel,-1);
sprintf(pBueffel,
"%s.detectorh %f \n", name, ObVal(self->aParameter,PARDDH));
Tcl_DStringAppend(&tString,pBueffel,-1);
sprintf(pBueffel,
"%s.d4h %f \n", name, ObVal(self->aParameter,PARD4H));
Tcl_DStringAppend(&tString,pBueffel,-1);
sprintf(pBueffel,
"%s.d5h %f \n", name, ObVal(self->aParameter,PARD5H));
Tcl_DStringAppend(&tString,pBueffel,-1);
sprintf(pBueffel,
"%s.anah %f \n", name, ObVal(self->aParameter,PARANA));
Tcl_DStringAppend(&tString,pBueffel,-1);
sprintf(pBueffel,
"%s.anad %f \n", name, ObVal(self->aParameter,PARADIS));
Tcl_DStringAppend(&tString,pBueffel,-1);
sprintf(pBueffel,
"%s.anaflag %f \n", name, ObVal(self->aParameter,ANAFLAG));
Tcl_DStringAppend(&tString,pBueffel,-1);
sprintf(pBueffel,
"%s.c2h %f \n", name, ObVal(self->aParameter,PARDDD));
Tcl_DStringAppend(&tString,pBueffel,-1);
sprintf(pBueffel,
"%s.aomconst %f \n", name, ObVal(self->aParameter,PARAOM));
Tcl_DStringAppend(&tString,pBueffel,-1);
SCWrite(pCon,Tcl_DStringValue(&tString),eValue);
Tcl_DStringFree(&tString);
}
/*------------------------------------------------------------------------*/
static void A2TKill(void *pData)
{
pAmor2T self = (pAmor2T) pData;
if(self == NULL)
return;
if(self->pDes)
DeleteDescriptor(self->pDes);
if(self->pDriv)
free(self->pDriv);
if(self->aParameter)
ObParDelete(self->aParameter);
free(self);
}
/*--------------------------------------------------------------------------
Initialization: All is done from the Factory function. This takes an Tcl
array as parameter which is supposed to hold the names of all motors.
This must fail if one of the motors cannot be accessed.
--------------------------------------------------------------------------*/
int Amor2TFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pAmor2T pNew, pAOM = NULL;
int i, iRet;
char pBueffel[512];
char *pMot = NULL;
if(argc < 4)
{
SCWrite(pCon,
"ERROR: Insufficient number of arguments to Amor2tFactory",
eError);
return 0;
}
/* allocate space ..............*/
pNew = (pAmor2T)malloc(sizeof(Amor2T));
if(!pNew)
{
SCWrite(pCon,"ERROR: out of memory in Amor2TFactory",eError);
return 0;
}
memset(pNew,0,sizeof(Amor2T));
pNew->pDes = CreateDescriptor("Amor2T");
pNew->aParameter = ObParCreate(MAXPAR);
pNew->pDriv = CreateDrivableInterface();
if( (!pNew->pDes) || (!pNew->aParameter) || (!pNew->pDriv) )
{
SCWrite(pCon,"ERROR: out of memory in Amor2TFactory",eError);
A2TKill(pNew);
return 0;
}
/* find the motors*/
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"mom",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for mom motr found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTMOM] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTMOM])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"som",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for som motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTSOM] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTSOM])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"coz",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for coz motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTCOZ] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTCOZ])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"cox",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for cox motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTCOX] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTCOX])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"stz",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for stz motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTSTZ] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTSTZ])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"soz",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for soz motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTSOZ] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTSOZ])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"d4b",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for d4b motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTD4B] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTD4B])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"d5b",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for d5b motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTD5B] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTD5B])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"com",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for com motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTCOM] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTCOM])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"aoz",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for aoz motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTAOZ] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTAOZ])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"aom",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for aom motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTAOM] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTAOM])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
pMot = Tcl_GetVar2(pSics->pTcl,argv[2],"c3z",TCL_GLOBAL_ONLY);
if(!pMot)
{
SCWrite(pCon,"ERROR: no value for c3z motor found",eError);
A2TKill(pNew);
return 0;
}
pNew->aEngine[MOTC3Z] = FindMotor(pSics,pMot);
if(!pNew->aEngine[MOTC3Z])
{
sprintf(pBueffel,"ERROR: motor %s NOT found!", pMot);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
/* initialize parameters */
ObParInit(pNew->aParameter,PARDS,"detectord",1400.,usMugger);
ObParInit(pNew->aParameter,PARDH,"sampleh",50.,usMugger);
ObParInit(pNew->aParameter,PARDD4,"d4d",100.,usMugger);
ObParInit(pNew->aParameter,PARDD5,"d5d",200.,usMugger);
ObParInit(pNew->aParameter,PARINT,"interrupt",0.,usMugger);
ObParInit(pNew->aParameter,PARDDH,"detectorh",40.,usMugger);
ObParInit(pNew->aParameter,PARD4H,"d4h",40.,usMugger);
ObParInit(pNew->aParameter,PARD5H,"d5h",400.,usMugger);
ObParInit(pNew->aParameter,PARANA,"anah",400.,usMugger);
ObParInit(pNew->aParameter,PARADIS,"anad",600.,usMugger);
ObParInit(pNew->aParameter,ANAFLAG,"anaflag",-1.,usMugger);
ObParInit(pNew->aParameter,PARDDD,"c2h",100.,usMugger);
ObParInit(pNew->aParameter,PARAOM,"aomconst",3.,usMugger);
/* initialize interfaces */
pNew->pDes->GetInterface = A2TGetInterface;
pNew->pDes->SaveStatus = A2TSave;
pNew->pDriv->Halt = A2THalt;
pNew->pDriv->CheckLimits = A2TCheck;
pNew->pDriv->SetValue = A2TSetValue;
pNew->pDriv->CheckStatus = A2TStatus;
pNew->pDriv->GetValue = A2TGetValue;
/* copy data structure for second command for aom2t */
pAOM = (pAmor2T)malloc(sizeof(Amor2T));
if(!pAOM)
{
A2TKill(pNew);
SCWrite(pCon,"ERROR: out of memory in Amor2TFactory",eError);
return 0;
}
memcpy(pAOM,pNew,sizeof(Amor2T));
pAOM->pDriv = CreateDrivableInterface();
pAOM->pDes = CreateDescriptor("Amor2T");
if(!pAOM->pDriv || !pAOM->pDes )
{
A2TKill(pNew);
SCWrite(pCon,"ERROR: out of memory in Amor2TFactory",eError);
return 0;
}
/* set modified interface functions */
pAOM->pDes->GetInterface = A2TGetInterface;
pAOM->pDriv->Halt = A2THalt;
pAOM->pDriv->CheckLimits = ANA2TCheck;
pAOM->pDriv->SetValue = ANA2TSetValue;
pAOM->pDriv->GetValue = ANA2TGetValue;
pAOM->pDriv->CheckStatus = A2TStatus;
/* install commands */
iRet = AddCommand(pSics,argv[1],
Amor2TAction,A2TKill,pNew);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate command %s NOT created",
argv[1]);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
iRet = AddCommand(pSics,argv[3],
Amor2TAction,free,pAOM);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate command %s NOT created",
argv[1]);
SCWrite(pCon,pBueffel,eError);
A2TKill(pNew);
return 0;
}
return 1;
}
/*----------------------------------------------------------------------*/
int Amor2TAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pAmor2T self = (pAmor2T)pData;
char pBueffel[256];
float fVal;
double dVal;
ObPar *pPar = NULL;
int iRet;
assert(self);
if(argc > 1)
{
strtolower(argv[1]);
/* deal with list */
if(strcmp(argv[1],"list") == 0)
{
A2TList(self,pCon,argv[0]);
return 1;
}
/* otherwise it should be a parameter command */
if(argc >= 3)
{
iRet = Tcl_GetDouble(pSics->pTcl,argv[2],&dVal);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: failed to convert %s to number",
argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = ObParSet(self->aParameter,argv[0],argv[1],(float)dVal,pCon);
if(iRet)
{
SCSendOK(pCon);
}
return iRet;
}
else
{
pPar = ObParFind(self->aParameter,argv[1]);
if(!pPar)
{
sprintf(pBueffel,"ERROR: parameter %s NOT found",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
sprintf(pBueffel,"%s.%s = %f",argv[0],pPar->name, pPar->fVal);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
}
else
{
fVal = self->pDriv->GetValue(self,pCon);
sprintf(pBueffel," %s = %f", argv[0], fVal);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
}

22
amor2t.h Normal file
View File

@ -0,0 +1,22 @@
/*-------------------------------------------------------------------------
A m o r 2 T
A class for controlling the two theta movement of a reflectometer.
Especially the AMOR reflectometer at SINQ. For details see the file
amor2t.tex. DO NOT TOUCH! This file is automatically created from amor2t.w
with nuweb.
Mark Koennecke, September 1999
---------------------------------------------------------------------------*/
#ifndef AMOR2T
#define AMOR2T
typedef struct __AMOR2T *pAmor2T;
int Amor2TFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int Amor2TAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
void Amor2TKill(void *pData);
#endif

55
amor2t.i Normal file
View File

@ -0,0 +1,55 @@
/*--------------------------------------------------------------------------
A m o r 2 T . i
Internal data structure definitions for Amor2T. For details see amor2t.tex.
DO NOT TOUCH! This file is automatically created from amor2t.w.
Mark Koennecke, September 1999
----------------------------------------------------------------------------*/
/* distance detector sample */
#define PARDS 0
/* constant height of sample: height = PARDH + MOTSOZ + MOTSTZ */
#define PARDH 1
/* distance diaphragm 4 - sample */
#define PARDD4 2
/* distance to diaphragm 5 */
#define PARDD5 3
/* interrupt to issue when a motor fails on this */
#define PARINT 4
/* base height of counter station */
#define PARDDH 5
/* height of D4 */
#define PARD4H 6
/* height of D5 */
#define PARD5H 7
/* base height of analyzer */
#define PARANA 8
/* distance of analyzer from sample */
#define PARADIS 9
/* flag analyzer calculation on/off */
#define ANAFLAG 10
/* constant for second detector */
#define PARDDD 11
/* constant part of AOM */
#define PARAOM 12
typedef struct {
pMotor pMot;
char pName[80];
float fTarget;
}MotEntry, *pMotEntry;
typedef struct __AMOR2T {
pObjectDescriptor pDes;
pIDrivable pDriv;
pMotor aEngine[MAXMOT];
MotEntry toStart[MAXMOT];
int iStart;
ObPar *aParameter;
}Amor2T;

204
amor2t.tex Normal file
View File

@ -0,0 +1,204 @@
\subsection{AMOR Two Theta}
AMOR is SINQ's new reflectometer. It has the peculiar feature that the
two theta movement of the detector is expressed in translations along
the reflectometer base axis and the detector height. Additionally the
detector is tilted. The height of two diaphragms has to be adjusted as
well. And, in polarizing mode, the analyzer has to be operated as
well. Quite a complicated movement. I fear this module may only be
useful for AMOR, but may be, other reflectometers may profit as well.
This object implements this complex movement as a virtual motor.
The following formulas are used for the necessary calculations:
\begin{eqnarray}
delta height & = & h_{s} - \sin \alpha \\
delta x & = & |x_{c} - x_{s}| - R \cos \alpha \\
omega & = & -2 MOM + 2 SOM \\
\end{eqnarray}
with
\begin{eqnarray}
h_{s} & = & \tan(2MOM)|x_{c} - x_{s}| \\
R & = & \sqrt{hs^{2} - |x_{c} - x_{s}|^{2}} \\
\alpha & = & ATT - 2SOM \\
\beta & = & 180 - 90 - 2MOM \\
MOM & = & polarizer \omega \\
SOM & = & sample \omega \\
x_{c} & = & counter position \\
x_{s} & = & sample position\\
\end{eqnarray}
The same equations hold true for the calculations of the diaphragm
heights, just replace the distances. The equations for the analyzer
are not yet known.
Due to this complicated movement this module needs to know about a lot
of motors and a lot of parameters. The distances of the various
components need to be modified at run time in order to allow for
configuration changes. These are not motorized but must be entered
manually.
\subsubsection{Data Structures}
Consequently data structures are complex. The first data structure
used is an entry in an array of motors to start:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$putput {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct {@\\
\mbox{}\verb@ pMotor pMot;@\\
\mbox{}\verb@ char pName[80];@\\
\mbox{}\verb@ float fTarget;@\\
\mbox{}\verb@ }MotEntry, *pMotEntry;@\\
\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{description}
\item[pMot] is a pointer to the motors data structure.
\item[pName] is the name of the motor to start.
\item[fTarget] is the target value for the motor.
\end{description}
The next data structure is the class data structure for amor2t:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$amoredata {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __AMOR2T {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ pIDrivable pDriv;@\\
\mbox{}\verb@ pMotor aEngine[MAXMOT];@\\
\mbox{}\verb@ MotEntry toStart[MAXMOT];@\\
\mbox{}\verb@ int iStart;@\\
\mbox{}\verb@ ObPar *aParameter;@\\
\mbox{}\verb@ }Amor2T;@\\
\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{description}
\item[pDes] The standard SICS object descriptor.
\item[pDriv] The drivable interface. The functions defined for the
drivable interface implement most of the work of this class.
\item[aEngine] An array of pointers to the motor data structures this
class has to deal with. The proper initialization of this is taken
care of during the initialization of the object.
\item[toStart] An array of motors to start when all calculations have
been performed.
\item[iStart] The number of valid entries in toStart.
\item[aParameter] An array of parameters for this object.
\end{description}
\subsubsection{The Interface}
The interface to this module is quite primitive. Most of the
functionality is hidden in the drivable interface. So there are only
functions for interacting with the interpreter.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
$\langle$amorinterface {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __AMOR2T *pAmor2T;@\\
\mbox{}\verb@@\\
\mbox{}\verb@ int Amor2TFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int Amor2TAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ void Amor2TKill(void *pData); @\\
\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@"amor2t.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
\mbox{}\verb@ A m o r 2 T . i@\\
\mbox{}\verb@ Internal data structure definitions for Amor2T. For details see amor2t.tex.@\\
\mbox{}\verb@ DO NOT TOUCH! This file is automatically created from amor2t.w.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1999@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@@\\
\mbox{}\verb@/* distance detector sample */@\\
\mbox{}\verb@#define PARDS 0@\\
\mbox{}\verb@/* constant height of sample: height = PARDH + MOTSOZ + MOTSTZ */@\\
\mbox{}\verb@#define PARDH 1@\\
\mbox{}\verb@/* distance diaphragm 4 - sample */@\\
\mbox{}\verb@#define PARDD4 2@\\
\mbox{}\verb@/* distance to diaphragm 5 */@\\
\mbox{}\verb@#define PARDD5 3@\\
\mbox{}\verb@/* interrupt to issue when a motor fails on this */@\\
\mbox{}\verb@#define PARINT 4@\\
\mbox{}\verb@/* base height of counter station */@\\
\mbox{}\verb@#define PARDDH 5@\\
\mbox{}\verb@/* height of D4 */@\\
\mbox{}\verb@#define PARD4H 6@\\
\mbox{}\verb@/* height of D5 */@\\
\mbox{}\verb@#define PARD5H 7@\\
\mbox{}\verb@/* base height of analyzer */@\\
\mbox{}\verb@#define PARANA 8@\\
\mbox{}\verb@/* distance of analyzer from sample */@\\
\mbox{}\verb@#define PARADIS 9@\\
\mbox{}\verb@/* flag analyzer calculation on/off */@\\
\mbox{}\verb@#define ANAFLAG 10@\\
\mbox{}\verb@/* constant for second detector */@\\
\mbox{}\verb@#define PARDDD 11@\\
\mbox{}\verb@/* constant part of AOM */@\\
\mbox{}\verb@#define PARAOM 12@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$putput {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$amoredata {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap5}
\verb@"amor2t.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ A m o r 2 T@\\
\mbox{}\verb@ A class for controlling the two theta movement of a reflectometer. @\\
\mbox{}\verb@ Especially the AMOR reflectometer at SINQ. For details see the file @\\
\mbox{}\verb@ amor2t.tex. DO NOT TOUCH! This file is automatically created from amor2t.w@\\
\mbox{}\verb@ with nuweb.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1999@\\
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef AMOR2T@\\
\mbox{}\verb@#define AMOR2T@\\
\mbox{}\verb@@$\langle$amorinterface {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

150
amor2t.w Normal file
View File

@ -0,0 +1,150 @@
\subsection{AMOR Two Theta}
AMOR is SINQ's new reflectometer. It has the peculiar feature that the
two theta movement of the detector is expressed in translations along
the reflectometer base axis and the detector height. Additionally the
detector is tilted. The height of two diaphragms has to be adjusted as
well. And, in polarizing mode, the analyzer has to be operated as
well. Quite a complicated movement. I fear this module may only be
useful for AMOR, but may be, other reflectometers may profit as well.
This object implements this complex movement as a virtual motor.
The following formulas are used for the necessary calculations:
\begin{eqnarray}
delta height & = & h_{s} - \sin \alpha \\
delta x & = & |x_{c} - x_{s}| - R \cos \alpha \\
omega & = & -2 MOM + 2 SOM \\
\end{eqnarray}
with
\begin{eqnarray}
h_{s} & = & \tan(2MOM)|x_{c} - x_{s}| \\
R & = & \sqrt{hs^{2} - |x_{c} - x_{s}|^{2}} \\
\alpha & = & ATT - 2SOM \\
\beta & = & 180 - 90 - 2MOM \\
MOM & = & polarizer \omega \\
SOM & = & sample \omega \\
x_{c} & = & counter position \\
x_{s} & = & sample position\\
\end{eqnarray}
The same equations hold true for the calculations of the diaphragm
heights, just replace the distances. The equations for the analyzer
are not yet known.
Due to this complicated movement this module needs to know about a lot
of motors and a lot of parameters. The distances of the various
components need to be modified at run time in order to allow for
configuration changes. These are not motorized but must be entered
manually.
\subsubsection{Data Structures}
Consequently data structures are complex. The first data structure
used is an entry in an array of motors to start:
@d putput @{
typedef struct {
pMotor pMot;
char pName[80];
float fTarget;
}MotEntry, *pMotEntry;
@}
\begin{description}
\item[pMot] is a pointer to the motors data structure.
\item[pName] is the name of the motor to start.
\item[fTarget] is the target value for the motor.
\end{description}
The next data structure is the class data structure for amor2t:
@d amoredata @{
typedef struct __AMOR2T {
pObjectDescriptor pDes;
pIDrivable pDriv;
pMotor aEngine[MAXMOT];
MotEntry toStart[MAXMOT];
int iStart;
ObPar *aParameter;
}Amor2T;
@}
\begin{description}
\item[pDes] The standard SICS object descriptor.
\item[pDriv] The drivable interface. The functions defined for the
drivable interface implement most of the work of this class.
\item[aEngine] An array of pointers to the motor data structures this
class has to deal with. The proper initialization of this is taken
care of during the initialization of the object.
\item[toStart] An array of motors to start when all calculations have
been performed.
\item[iStart] The number of valid entries in toStart.
\item[aParameter] An array of parameters for this object.
\end{description}
\subsubsection{The Interface}
The interface to this module is quite primitive. Most of the
functionality is hidden in the drivable interface. So there are only
functions for interacting with the interpreter.
@d amorinterface @{
typedef struct __AMOR2T *pAmor2T;
int Amor2TFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int Amor2TAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
void Amor2TKill(void *pData);
@}
@o amor2t.i @{
/*--------------------------------------------------------------------------
A m o r 2 T . i
Internal data structure definitions for Amor2T. For details see amor2t.tex.
DO NOT TOUCH! This file is automatically created from amor2t.w.
Mark Koennecke, September 1999
----------------------------------------------------------------------------*/
/* distance detector sample */
#define PARDS 0
/* constant height of sample: height = PARDH + MOTSOZ + MOTSTZ */
#define PARDH 1
/* distance diaphragm 4 - sample */
#define PARDD4 2
/* distance to diaphragm 5 */
#define PARDD5 3
/* interrupt to issue when a motor fails on this */
#define PARINT 4
/* base height of counter station */
#define PARDDH 5
/* height of D4 */
#define PARD4H 6
/* height of D5 */
#define PARD5H 7
/* base height of analyzer */
#define PARANA 8
/* distance of analyzer from sample */
#define PARADIS 9
/* flag analyzer calculation on/off */
#define ANAFLAG 10
/* constant for second detector */
#define PARDDD 11
/* constant part of AOM */
#define PARAOM 12
@<putput@>
@<amoredata@>
@}
@o amor2t.h @{
/*-------------------------------------------------------------------------
A m o r 2 T
A class for controlling the two theta movement of a reflectometer.
Especially the AMOR reflectometer at SINQ. For details see the file
amor2t.tex. DO NOT TOUCH! This file is automatically created from amor2t.w
with nuweb.
Mark Koennecke, September 1999
---------------------------------------------------------------------------*/
#ifndef AMOR2T
#define AMOR2T
@<amorinterface@>
#endif
@}

23
amorpar.tcl Normal file
View File

@ -0,0 +1,23 @@
#--------------------------------------------------------------------------
# A SICS-tcl-macro script for formatting the parameters for the
# reflectometer AMOR's status display.
#
# Mark Koennecke, October 1999
#-------------------------------------------------------------------------
proc amorpar {} {
lappend list "amorpar == "
lappend list [lastscancommand] ";"
catch {scan getvars} msg
lappend list $msg ";"
lappend list [xxxscan getfile] ";"
lappend list [sicstime] ";"
set ret [catch {temperature} msg]
if {$ret == 0} {
lappend list $msg
}
set ret [catch {magnet} msg]
if {$ret == 0} {
lappend list $msg
}
return [join $list]
}

140
amorscan.c Normal file
View File

@ -0,0 +1,140 @@
/*-------------------------------------------------------------------------
A M O R S C A N
An adaption of the general scan routine to deal with special issues at
the reflectometer AMOR at SINQ.
copyright: see copyright.h
Mark Koennecke, September 1999
--------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include "fortify.h"
#include "sics.h"
#include "scan.h"
#include "scan.i"
#include "HistMem.h"
#include "nxamor.h"
#include "amorscan.h"
/*--------------------------------------------------------------------*/
static int AmorHeader(pScanData self)
{
return WriteAmorHeader(self->pFile, self->pCon);
}
/*--------------------------------------------------------------------*/
static int AmorPoints(pScanData self, int iP)
{
/* write only at last scan point */
if((iP+1) >= self->iNP)
{
return WriteAmorScan(self->pFile,self->pCon,self);
}
}
/*--------------------------------------------------------------------*/
static int AmorCollect(pScanData self, int iP)
{
pVarEntry pVar = NULL;
void *pDings;
int i, iRet, status;
float fVal;
char pStatus[512], pItem[20];
char pHead[512];
CountEntry sCount;
assert(self);
assert(self->pCon);
/* prepare output header */
sprintf(pHead,"%-5.5s","NP");
sprintf(pStatus,"%-5d",iP);
/* loop over all scan variables */
status = 1;
for(i = 0; i < self->iScanVar; i++)
{
DynarGet(self->pScanVar,i,&pDings);
pVar = (pVarEntry)pDings;
if(pVar)
{
fVal = pVar->pInter->GetValue(pVar->pObject,self->pCon);
pVar->fData[iP] = fVal;
sprintf(pItem,"%-10.10s",pVar->Name);
strcat(pHead,pItem);
sprintf(pItem,"%-10.3f",fVal);
strcat(pStatus,pItem);
}
}
/* store counter data */
/* monitors */
for(i = 1; i < 10; i++)
{
sCount.Monitors[i-1] = GetMonitor((pCounter)self->pCounterData,i,
self->pCon);
}
if( self->iChannel != 0 && self->iChannel != -10 )
{
sCount.Monitors[self->iChannel - 1] =
GetCounts((pCounter)self->pCounterData,
self->pCon);
}
/* counter1 */
strcat(pHead,"Counter1 ");
sCount.lCount = GetCounts((pCounter)self->pCounterData,self->pCon);
sprintf(pItem,"%-15d",sCount.lCount);
strcat(pStatus,pItem);
/*
WARNING
Assignements have to be checked when the Schlumpfes are
ready putting the counter box together.
*/
/* counter2 */
strcat(pHead,"Counter2 ");
sCount.Monitors[0] = GetMonitor((pCounter)self->pCounterData,
1,self->pCon);
sprintf(pItem,"%-15d",sCount.Monitors[0]);
strcat(pStatus,pItem);
/* monitors */
sCount.Monitors[3] = GetMonitor((pCounter)self->pCounterData,
2,self->pCon);
sCount.Monitors[4] = GetMonitor((pCounter)self->pCounterData,
3,self->pCon);
/* get time */
sCount.fTime = GetCountTime((pCounter)self->pCounterData,
self->pCon);
strcat(pHead,"Monitor1 ");
sprintf(pItem,"%-12d",sCount.Monitors[3]);
strcat(pStatus,pItem);
strcat(pHead,"Monitor2 ");
sprintf(pItem,"%-12d",sCount.Monitors[4]);
strcat(pStatus,pItem);
strcat(pHead,"Time ");
sprintf(pItem,"%-6.1f",sCount.fTime);
strcat(pStatus,pItem);
/* write progress */
strcat(pHead,"\n");
strcat(pStatus,"\n");
SCWrite(self->pCon,pHead,eWarning);
SCWrite(self->pCon,pStatus,eWarning);
/* stow away */
DynarReplace(self->pCounts,self->iCounts,&sCount,sizeof(CountEntry));
self->iCounts++;
return 1;
}
/*-----------------------------------------------------------------------*/
int ConfigureAmor(pScanData self)
{
self->WriteHeader = AmorHeader;
self->WriteScanPoints = AmorPoints;
self->CollectScanData = AmorCollect;
strcpy(self->ext,".hdf");
return 1;
}

15
amorscan.h Normal file
View File

@ -0,0 +1,15 @@
/*-----------------------------------------------------------------------
A M O R S C A N
Adaption of the scan command to do things specific to the
reflectometer AMOR at SINQ.
Mark Koennecke, September 1999
-----------------------------------------------------------------------*/
#ifndef AMORSCAN
#define AMORSCAN
int ConfigureAmor(pScanData pScan);
#endif

71
amorscan.tex Normal file
View File

@ -0,0 +1,71 @@
\subsection{Amor Scan}
This is a special adaption of the general scan routines for the
reflectometer AMOR at SINQ. It works by replacing the configurable
routines in the general scan command with special ones, suited to the
reflectometers purpose. There are several adaptions to the standard
scan command:
\begin{itemize}
\item Data is written to NeXus files instead of ASCII files.
\item There are two counters to keep track of.
\item Furthermore stubs are provided for dealing with spin flippers.
\end{itemize}
In order to keep track of counters and monitors the following
convention has been devised:
\begin{itemize}
\item GetCounts gets the main detector.
\item GetMonitor 0 the second detector
\item GetMonitor 1 the first detector other spin
\item GetMonitor 2 the second detector other spin
\item GetMonitor 3 the first monitor
\item GetMonitor 4 the second monitor
\end{itemize}
Thus the monitor channels are used to keep the additional counter
information.
This module provides only one external function:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$amorscan {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int ConfigureAmor(pScanData pScan);@\\
\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}
which configures the variable fields and function pointers in pScan to
functions defined in this module. These then do the right thing. This
module is also an example of how the scan command can be configured to do
tricks based on the syntax and hooks defined in scan.*.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
\verb@"amorscan.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-----------------------------------------------------------------------@\\
\mbox{}\verb@ A M O R S C A N@\\
\mbox{}\verb@ Adaption of the scan command to do things specific to the@\\
\mbox{}\verb@ reflectometer AMOR at SINQ.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1999@\\
\mbox{}\verb@-----------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef AMORSCAN@\\
\mbox{}\verb@#define AMORSCAN@\\
\mbox{}\verb@@$\langle$amorscan {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

57
amorscan.w Normal file
View File

@ -0,0 +1,57 @@
\subsection{Amor Scan}
This is a special adaption of the general scan routines for the
reflectometer AMOR at SINQ. It works by replacing the configurable
routines in the general scan command with special ones, suited to the
reflectometers purpose. There are several adaptions to the standard
scan command:
\begin{itemize}
\item Data is written to NeXus files instead of ASCII files.
\item There are two counters to keep track of.
\item Furthermore stubs are provided for dealing with spin flippers.
\end{itemize}
In order to keep track of counters and monitors the following
convention has been devised:
\begin{itemize}
\item GetCounts gets the main detector.
\item GetMonitor 0 the second detector
\item GetMonitor 1 the first detector other spin
\item GetMonitor 2 the second detector other spin
\item GetMonitor 3 the first monitor
\item GetMonitor 4 the second monitor
\end{itemize}
Thus the monitor channels are used to keep the additional counter
information.
This module provides only one external function:
@d amorscan @{
int ConfigureAmor(pScanData pScan);
@}
which configures the variable fields and function pointers in pScan to
functions defined in this module. These then do the right thing. This
module is also an example of how the scan command can be configured to do
tricks based on the syntax and hooks defined in scan.*.
@o amorscan.h @{
/*-----------------------------------------------------------------------
A M O R S C A N
Adaption of the scan command to do things specific to the
reflectometer AMOR at SINQ.
Mark Koennecke, September 1999
-----------------------------------------------------------------------*/
#ifndef AMORSCAN
#define AMORSCAN
@<amorscan@>
#endif
@}

919
amorstat.c Normal file
View File

@ -0,0 +1,919 @@
/*--------------------------------------------------------------------------
A M O R S T A T U S
The implementation file for the amor status display facilitator module. The
reflectometer AMOR needs some advanced feautures for its status display.
These needs are taken care of here.
copyright: see copyright.h
Mark Koennecke, September 1999
As AMOR's histogram memory becomes too big in tof mode to transfer it
for status information the collapse and subsample functionalities have
been moved to the histogram memory. This code had to be modified to
call SINQHMProject directly.
Mark Koennecke, August 2001
--------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <tcl.h>
#include "fortify.h"
#include "sics.h"
#include "counter.h"
#include "stringdict.h"
#include "HistMem.h"
#include "HistMem.i"
#include "HistDriv.i"
#include "hardsup/sinqhm.h"
#include "sinqhmdriv.i"
#include "scan.h"
#include "lld.h"
#include "amorstat.i"
#include "amorstat.h"
/*-------------------------------------------------------------------------
A static which determines if we are in TOF or scan mode.
*/
static int iTOF = 0;
static pHistMem pHMHM = NULL;
/*-------------------------------------------------------------------------*/
static int HMCountStartCallback(int iEvent, void *pEvent, void *pUser)
{
SConnection *pCon = (SConnection *)pUser;
const float *fTime = NULL;
int *iTime = NULL;
int iLength, iRet, i;
assert(pCon);
if(iEvent == COUNTSTART)
{
/* send current time binning */
iTOF = 1;
fTime = GetHistTimeBin(pHMHM,&iLength);
iTime = (int *)malloc((iLength+1)*sizeof(int));
if( (!fTime) || (!iTime))
{
return 0;
}
iTime[0] = htonl(iLength);
for(i = 0 ; i < iLength; i++)
{
iTime[i+1] = htonl((int)((fTime[i]/10.)*65536.));
}
/* send new time binning to all clients */
SCWrite(pCon,"TOFClear",eError);
SCWriteUUencoded(pCon,"arrowaxis_time",iTime,
(iLength+1)*sizeof(int));
free(iTime);
}
return 1;
}
/*-------------------------------------------------------------------------*/
static int ScanStartCallback(int iEvent, void *pEvent, void *pUser)
{
float *fAxis = NULL;
int *iAxis = NULL;
int iLength, iRet, i;
char pBueffel[80], pName[40];
SConnection *pCon = (SConnection *)pUser;
pScanData pScan = (pScanData)pEvent;
assert(pCon);
assert(pScan);
if(iEvent == SCANSTART)
{
iTOF = 0;
/* send current axis */
iLength = GetScanNP(pScan);
fAxis = (float *)malloc((iLength+1)*sizeof(float));
iAxis = (int *)malloc((iLength+1)*sizeof(int));
if( (!fAxis) || (!iAxis))
{
return 0;
}
iAxis[0] = htonl(iLength);
GetSoftScanVar(pScan,0,fAxis,iLength);
GetScanVarName(pScan,0,pName,39);
sprintf(pBueffel,"arrowaxis_%s",pName);
for(i = 0 ; i < iLength; i++)
{
iAxis[i+1] = htonl((int)(fAxis[i]*65536.));
}
/* send new axis to client */
SCWrite(pCon,"SCANClear",eError);
SCWriteUUencoded(pCon,pBueffel,iAxis,
(iLength+1)*sizeof(int));
free(iAxis);
free(fAxis);
}
return 1;
}
/*------------------------------------------------------------------------*/
static int ScanPointCallback(int iEvent, void *pEvent, void *pUser)
{
long *lData = NULL;
int *iData = NULL;
int iLength, iRet, i;
SConnection *pCon = (SConnection *)pUser;
pScanData pScan = (pScanData)pEvent;
assert(pCon);
assert(pScan);
if( (iEvent == SCANPOINT) || (iEvent == SCANEND) )
{
/* send current data */
iTOF = 0;
iLength = GetScanNP(pScan);
lData = (long *)malloc((iLength+1)*sizeof(long));
iData = (int *)malloc((iLength+1)*sizeof(int));
if( (!lData) || (!iData))
{
return 0;
}
iData[0] = htonl(iLength);
GetScanCounts(pScan,lData,iLength);
for(i = 0 ; i < iLength; i++)
{
iData[i+1] = htonl((int)(lData[i]));
}
/* send counts to client */
SCWriteUUencoded(pCon,"arrow_spinupup",iData,
(iLength+1)*sizeof(int));
/* send counts for other detector */
GetScanMonitor(pScan,2,lData,iLength);
for(i = 0 ; i < iLength; i++)
{
iData[i+1] = htonl((int)(lData[i]));
}
SCWriteUUencoded(pCon,"arrow_spinuplo",iData,
(iLength+1)*sizeof(int));
/* to do: check for polarization and send spinlo */
free(iData);
free(lData);
}
return 1;
}
/*------------------------------------------------------------------------*/
static int SendLoadedData(pAmorStat self, SConnection *pCon)
{
int i, iRet, *iData = NULL;
char pBueffel[80];
UserData ud;
SCWrite(pCon,"loaded_CLEAR",eValue);
iRet = LLDnodePtr2First(self->iUserList);
while(iRet != 0)
{
LLDnodeDataTo(self->iUserList,&ud);
iData = (int *)malloc((ud.iNP*2 + 1)*sizeof(int));
if(!iData)
{
return 0;
}
iData[0] = htonl(ud.iNP);
for(i = 0; i < ud.iNP; i++)
{
iData[i+1] = htonl((int)(ud.fX[i]*65536));
iData[i+1+ud.iNP] = htonl((int)(ud.fY[i]*65536));
}
sprintf(pBueffel,"loaded_%s",ud.name);
SCWriteUUencoded(pCon,pBueffel,iData,(ud.iNP*2+1)*sizeof(int));
iRet = LLDnodePtr2Next(self->iUserList);
}
}
/*------------------------------------------------------------------------*/
static int LoadCallback(int iEvent, void *pEvent, void *pUser)
{
pAmorStat pAS = NULL;
SConnection *pCon = NULL;
if(iEvent == FILELOADED)
{
pAS = (pAmorStat)pEvent;
pCon = (SConnection *)pUser;
assert(pAS);
assert(pCon);
SendLoadedData(pAS,pCon);
}
return 1;
}
/*-------------------------------------------------------------------------*/
static void ClearUserData(pAmorStat self)
{
int iRet;
UserData ud;
iRet = LLDnodePtr2First(self->iUserList);
while(iRet != 0)
{
LLDnodeDataTo(self->iUserList,&ud);
if(ud.fX != NULL)
free(ud.fX);
if(ud.fY != NULL)
free(ud.fY);
if(ud.name != NULL)
free(ud.name);
iRet = LLDnodePtr2Next(self->iUserList);
}
LLDdelete(self->iUserList);
self->iUserList = LLDcreate(sizeof(UserData));
}
/*----------------------------------------------------------------------*/
void KillAmorStatus(void *pData)
{
pAmorStat self = (pAmorStat)pData;
if(!self)
return;
if(self->iUserList >= 0)
{
ClearUserData(self);
LLDdelete(self->iUserList);
}
if(self->pDes)
DeleteDescriptor(self->pDes);
if(self->pCall)
DeleteCallBackInterface(self->pCall);
free(self);
}
/*------------------------------------------------------------------*/
int AmorStatusFactory(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[])
{
pAmorStat pNew = NULL;
CommandList *pCom = NULL;
char pBueffel[256];
int iRet;
/* check number of arguments */
if(argc < 4)
{
sprintf(pBueffel,"ERROR: insufficient number of arguments to %s",
argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* allocate a new data structure */
pNew = (pAmorStat)malloc(sizeof(AmorStat));
if(!pNew)
{
sprintf(pBueffel,"ERROR: out of memory in %s",argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
memset(pNew,0,sizeof(AmorStat));
pNew->pDes = CreateDescriptor("AmorStatus");
pNew->iUserList = LLDcreate(sizeof(UserData));
pNew->pCall = CreateCallBackInterface();
if( (!pNew->pDes) || (pNew->iUserList < 0) || (!pNew->pCall) )
{
sprintf(pBueffel,"ERROR: out of memory in %s",argv[0]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
/* to locate the HM and the scan object */
pCom = FindCommand(pSics,argv[2]);
if(pCom)
{
if(pCom->pData)
{
if(!iHasType(pCom->pData,"ScanObject"))
{
sprintf(pBueffel,"ERROR: %s is NO scan object",argv[2]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
}
else
{
sprintf(pBueffel,"ERROR: %s is NO scan object",argv[2]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
}
else
{
sprintf(pBueffel,"ERROR: %s NOT found",argv[2]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
pNew->pScan = (pScanData)pCom->pData;
pCom = FindCommand(pSics,argv[3]);
if(pCom)
{
if(pCom->pData)
{
if(!iHasType(pCom->pData,"HistMem"))
{
sprintf(pBueffel,"ERROR: %s is NO histogram memory object",
argv[3]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
}
else
{
sprintf(pBueffel,"ERROR: %s is NO histogram memory object",
argv[3]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
}
else
{
sprintf(pBueffel,"ERROR: %s NOT found",argv[3]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
pNew->pHM = (pHistMem)pCom->pData;
pHMHM = (pHistMem)pCom->pData;
/* install command */
iRet = AddCommand(pSics,argv[1],
AmorStatusAction,KillAmorStatus,pNew);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate command %s NOT created",
argv[1]);
SCWrite(pCon,pBueffel,eError);
KillAmorStatus(pNew);
return 0;
}
return 1;
}
/*------------------------------------------------------------------*/
static int RegisterInterest(pAmorStat self, SConnection *pCon)
{
long lID;
pDummy pDum = NULL;
pICallBack pCall = NULL;
assert(self);
assert(pCon);
/* Register all the callbacks. Dependent on the state of
iTOF invoke the apropriate callbacks in order to force
an initial update.
*/
/* file load callback */
lID = RegisterCallback(self->pCall, FILELOADED, LoadCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics, self->pCall,lID);
SendLoadedData(self,pCon);
/* scan object */
pDum = (pDummy)self->pScan;
pCall = pDum->pDescriptor->GetInterface(pDum,CALLBACKINTERFACE);
if(pCall)
{
lID = RegisterCallback(pCall,SCANSTART,ScanStartCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics,pCall,lID);
lID = RegisterCallback(pCall,SCANPOINT,ScanPointCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics,pCall,lID);
lID = RegisterCallback(pCall,SCANEND,ScanPointCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics,pCall,lID);
if(iTOF == 0)
{
ScanStartCallback(SCANSTART,pDum,pCon);
ScanPointCallback(SCANPOINT,pDum,pCon);
}
}
pDum = (pDummy)self->pHM;
pCall = pDum->pDescriptor->GetInterface(pDum,CALLBACKINTERFACE);
if(pCall)
{
lID = RegisterCallback(pCall,COUNTSTART,HMCountStartCallback,
pCon, NULL);
SCRegister(pCon,pServ->pSics,pCall,lID);
if(iTOF == 1)
{
HMCountStartCallback(COUNTSTART,pDum,pCon);
}
}
return 1;
}
/*-----------------------------------------------------------------*/
static int FileLoad(pAmorStat self, SConnection *pCon,
char *name, double dScale)
{
char pBueffel[256], pDummy[50];
FILE *fd = NULL;
UserData ud;
int iNP, i;
float fDummy;
/* open the file */
fd = fopen(name,"r");
if(!fd)
{
sprintf(pBueffel,"ERROR: cannot open %s for reading",name);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* skip first line */
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"ERROR: premature end of file",eError);
fclose(fd);
return 0;
}
/* read number of points in second line */
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"ERROR: premature end of file",eError);
fclose(fd);
return 0;
}
sscanf(pBueffel,"%s %d",pDummy, &iNP);
/* allocate data */
ud.iNP = iNP;
ud.fX = (float *)malloc(iNP*sizeof(float));
ud.fY = (float *)malloc(iNP*sizeof(float));
ud.name = strdup(name);
/* skip two lines */
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"ERROR: premature end of file",eError);
fclose(fd);
return 0;
}
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"ERROR: premature end of file",eError);
fclose(fd);
return 0;
}
/* loop reading data */
for(i = 0; i < iNP; i++)
{
if(fgets(pBueffel,255,fd) == NULL)
{
SCWrite(pCon,"WARNING: premature end of file",eError);
break;
}
sscanf(pBueffel," %f %f %f",&ud.fX[i],&fDummy, &ud.fY[i]);
ud.fY[i] *= dScale;
}
fclose(fd);
/* enter ud into list */
LLDnodeInsertFrom(self->iUserList,&ud);
return 1;
}
/*-----------------------------------------------------------------
Collapse creates a 2D image from the detector by summing all time
channels together in any given detector.
*/
static int Collapse(pAmorStat self, SConnection *pCon)
{
HistInt *lData = NULL;
int i, i2, i3, iDim[MAXDIM], iIdx, iSum, status, length;
int *iImage = NULL, *iPtr;
pSINQHM pHist;
SinqHMDriv *pTata;
int iMax = -999999;
/* get size of our problem */
GetHistDim(self->pHM,iDim,&i3);
/* assert(i3 == 3); */
/* allocate some data */
length = 2 + iDim[0]*iDim[1];
iImage = (int *)malloc(length*sizeof(int));
if(iImage == NULL)
{
SCWrite(pCon,"ERROR: failed to allocate memory in Collapse",eError);
return 0;
}
memset(iImage,0,(2 + iDim[0]*iDim[1])*sizeof(int));
/* first two numbers are the dimension of the image */
iImage[0] = htonl(iDim[0]);
iImage[1] = htonl(iDim[1]);
if(isSINQHMDriv(self->pHM->pDriv))
{
/*
send a Project request to the histogram memory
*/
pTata = (SinqHMDriv *)self->pHM->pDriv->pPriv;
pHist = (pSINQHM)pTata->pMaster;
/*
The 3 in the following call has to be identical to
PROJECT__COLL in sinqhm_def.h
*/
status = SINQHMProject(pHist, 3, 0, iDim[0],
0, iDim[1], iImage+2, (length-2)*sizeof(int));
/*
Byte swapping
*/
for(i = 2; i < length; i++)
{
/*
if(iImage[i] > iMax){
iMax = iImage[i];
}
*/
iImage[i] = htonl(iImage[i]);
}
/*
printf("Collapsed maximum: %d\n",iMax);
*/
if(status != 1)
{
SCWrite(pCon,"ERROR: histogram memory refused to Collapse",eError);
return 0;
}
}
else
{
/*
we are in simulation and just create some random numbers
*/
for(i = 0; i < iDim[0]; i++)
{
for(i2 = 0; i2 < iDim[1]; i2++)
{
iIdx = i*iDim[1] + i2;
iImage[iIdx+2] = htonl(random());
/* iImage[iIdx+2] = htonl(77);*/
}
}
}
/* send image */
SCWriteUUencoded(pCon,"arrow_image",iImage,
((iDim[0]*iDim[1])+2)*sizeof(int));
free(iImage);
return 1;
}
/*-----------------------------------------------------------------
SendSingleTOF sends single detector data for TOF mode
*/
static int SendSingleTOF(pAmorStat self, SConnection *pCon)
{
HistInt *lData = NULL;
int i, i2, i3, iDim[MAXDIM], iIdx, iSum, status, length, nTime;
pSINQHM pHist;
SinqHMDriv *pTata;
int iMax = -999999;
const float *timebin;
HistInt *iData = NULL;
int iStart;
/* get size of our problem */
GetHistDim(self->pHM,iDim,&i3);
/* allocate some data */
timebin = GetHistTimeBin(self->pHM, &nTime);
if(nTime < 2) {
return 1;
}
length = 1 + 2*nTime;
iData = (HistInt *)malloc(length*sizeof(HistInt));
if(iData == NULL){
SCWrite(pCon,"ERROR: failed to allocate memory in SendSingleTOF",
eError);
return 0;
}
memset(iData,0,length*sizeof(int));
/* first number is the length of each single histogram */
iData[0] = htonl(nTime);
if(isSINQHMDriv(self->pHM->pDriv))
{
iStart = iDim[0]*iDim[1]*nTime;
GetHistogramDirect(self->pHM,pCon,0,iStart,
iStart + 2*nTime,&iData[1],2*nTime*sizeof(HistInt));
for(i = 1; i < length; i++)
{
iData[i] = htonl(iData[i]);
}
}
else
{
/*
we are in simulation and just create some random numbers
*/
for(i = 1; i < length; i++)
{
iData[i] = htonl(random());
}
}
/*
send, with a little trick to do two histograms.
*/
SCWriteUUencoded(pCon,"SING1",iData,
(nTime+1)*sizeof(int));
iData[nTime] = htonl(nTime);
SCWriteUUencoded(pCon,"SING2",&iData[nTime],
(nTime+1)*sizeof(int));
free(iData);
return 1;
}
/*-------------------------------------------------------------------
SubSample sums histogram data in the area defined by the rectangle
x1,y1 x2, y2. Summing is along the time axis.
*/
static int SubSample(pAmorStat self, SConnection *pCon,
char *name, int x1, int x2, int y1, int y2)
{
int iDim[MAXDIM], i, i2, i3, *iSum = NULL, iLang, *iPtr;
HistInt *lData = NULL;
int iLimit, status, nTime;
char pBueffel[132];
pSINQHM pHist;
SinqHMDriv *pTata;
const float *fTime;
/* get histogram dimensions */
GetHistDim(self->pHM,iDim,&i3);
fTime = GetHistTimeBin(self->pHM,&nTime);
iDim[i3] = nTime;
i3++;
assert(i3 == 3);
/* check limits */
if(x2 < x1){
i = x1;
x1 = x2;
x2 = i +1;
}
if(y2 < y1){
i = y1;
y1 = y2;
y2 = i + 1;
}
iLimit = 0;
if( x1 > iDim[0])
{
iLimit = 1;
x1 = iDim[0] - 1;
}
if(x1 < 0)
{
iLimit = 1;
x1 = 0;
}
if( x2 > iDim[0])
{
iLimit = 2;
x2 = iDim[0] - 1;
}
if(x2 < 0)
{
iLimit = 2;
x2 = 0;
}
if( y1 > iDim[1])
{
iLimit = 3;
y1 = iDim[1] - 1;
}
if(y1 < 0)
{
iLimit = 3;
y1 = 0;
}
if( y2 > iDim[1])
{
iLimit = 4;
y2 = iDim[1] - 1;
}
if(y2 < 0)
{
iLimit = 4;
y2 = 0;
}
if(iLimit != 0)
{
switch(iLimit)
{
case 1:
strcpy(pBueffel,"WARNING: limit violation on x1");
break;
case 2:
strcpy(pBueffel,"WARNING: limit violation on x2");
break;
case 3:
strcpy(pBueffel,"WARNING: limit violation on y1");
break;
case 4:
strcpy(pBueffel,"WARNING: limit violation on y2");
break;
}
SCWrite(pCon,pBueffel,eWarning);
}
/* allocate space for result */
iSum = (int *)malloc((iDim[2]+1)*sizeof(int));
if(!iSum)
{
SCWrite(pCon,"ERROR: out of memory in SubSample",eError);
return 0;
}
memset(iSum,0,(iDim[2]+1)*sizeof(int));
iSum[0] = htonl(iDim[2]);
if(isSINQHMDriv(self->pHM->pDriv))
{
/*
send project message to histogram memory
*/
pTata = (SinqHMDriv *)self->pHM->pDriv->pPriv;
pHist = (pSINQHM)pTata->pMaster;
status = SINQHMProject(pHist, 4, x1, x2-x1,
y1, y2-y1, iSum+1, iDim[2]*sizeof(int));
/*
convert to network byte order
*/
for(i = 1; i < iDim[2]+1; i++)
{
iSum[i] = htonl(iSum[i]);
}
if(status != 1)
{
SCWrite(pCon,"ERROR: histogram memory refused to SubSample",eError);
return 0;
}
}
else
{
/* do acouple of random numbers! */
for(i = 1; i < iDim[2]+1; i++)
{
iSum[i] = htonl(random());
}
}
/* send */
sprintf(pBueffel,"arrowsum_%s",name);
SCWriteUUencoded(pCon,pBueffel,iSum,(iDim[2]+1)*sizeof(int));
free(iSum);
return 1;
}
/*------------------------------------------------------------------*/
int AmorStatusAction(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[])
{
pAmorStat self = (pAmorStat)pData;
char pBueffel[512];
double dScale;
int iRet;
int x1, x2, y1, y2;
assert(self);
if(argc < 2)
{
sprintf(pBueffel,"ERROR: need argument to %s",argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
strtolower(argv[1]);
if(strcmp(argv[1],"interest") == 0)
{
RegisterInterest(self,pCon);
SCSendOK(pCon);
return 1;
}
else if(strcmp(argv[1],"load") == 0)
{
if(argc < 4)
{
sprintf(pBueffel,
"ERROR: need filename and scale argument to %s load",
argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetDouble(pSics->pTcl,argv[3],&dScale);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to scale factor",
argv[3]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
FileLoad(self,pCon,argv[2],dScale);
InvokeCallBack(self->pCall, FILELOADED,self);
SCSendOK(pCon);
}
else if(strcmp(argv[1],"collapse") == 0)
{
iRet = Collapse(self,pCon);
if(iRet)
{
SCSendOK(pCon);
}
return iRet;
}
else if(strcmp(argv[1],"sample") == 0)
{
if(argc < 7)
{
SCWrite(pCon,"ERROR: insufficent number of arguments to sample",
eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[3],&x1);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to int", argv[3]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[6],&y2);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to int", argv[6]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[4],&x2);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to int", argv[4]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[5],&y1);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: cannot convert %s to int", argv[5]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = SubSample(self,pCon,argv[2],x1,x2,y1,y2);
if(iRet)
SCSendOK(pCon);
return iRet;
}
else if(strcmp(argv[1],"singletof") == 0)
{
return SendSingleTOF(self,pCon);
}
else if(strcmp(argv[1],"sendloaded") == 0)
{
SendLoadedData(self,pCon);
return 1;
}
else if(strcmp(argv[1],"clear") == 0)
{
ClearUserData(self);
InvokeCallBack(self->pCall, FILELOADED,self);
SCSendOK(pCon);
}
else if(strcmp(argv[1],"tofmode") == 0)
{
HMCountStartCallback(COUNTSTART,NULL,pCon);
return 1;
}
else
{
sprintf(pBueffel,"ERROR: %s nor recognized as subcommand to %s",
argv[1], argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
return 1;
}

21
amorstat.h Normal file
View File

@ -0,0 +1,21 @@
/*------------------------------------------------------------------------
A M O R S T A T U S
Public definitions for the AMOR status display
facilitator object. DO NOT CHANGE. This file is automatically
created from amorstat.w.
Mark Koennecke, September 1999
---------------------------------------------------------------------*/
#ifndef AMORSTATUS
#define AMORSTATUS
int AmorStatusFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int AmorStatusAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
void KillAmorStatus(void *pData);
#endif

29
amorstat.i Normal file
View File

@ -0,0 +1,29 @@
/*------------------------------------------------------------------------
A M O R S T A T U S
Internal data structure definitions for the AMOR status display
facilitator object. DO NOT CHANGE. This file is automatically
created from amorstat.w.
Mark Koennecke, September 1999
---------------------------------------------------------------------*/
/*---------------------------------------------------------------------*/
typedef struct {
float *fX, *fY;
int iNP;
char *name;
}UserData, *pUserData;
/*---------------------------------------------------------------------*/
typedef struct __AMORSTAT {
pObjectDescriptor pDes;
pICallBack pCall;
int iUserList;
pScanData pScan;
pHistMem pHM;
int iTOF;
}AmorStat, *pAmorStat;

138
amorstat.tex Normal file
View File

@ -0,0 +1,138 @@
\subsection{Amor Status Display Support}
The reflectometer AMOR has a few unique status display requirements:
\begin{itemize}
\item In scan mode up to four detector counts curves must be shown for
the two counters in spin-up or spin-down mode. This needs to be
updated after each scan point.
\item Additionally user defined curves may need to be displayed.
\item The usual helper information muste be displayed.
\item In TOF mode it must be possible to define a region on the
detector whose summed counts are displayed versus the time
binning. This must be sent on request.
\end{itemize}
In order to cover all this a special object within SICS is required
which deals with all this and packages information in a status display
compliant way.
In order to do this the amorstatus object registers callbacks both
with the histogram memory and the scan object. These callback
functions are then responsible for updating the status displays. In
order for amorstatus to be able to do this, the client must register
itself with a special command.
In order to achieve all this some data structures are needed:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$asdata {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------*/@\\
\mbox{}\verb@ typedef struct {@\\
\mbox{}\verb@ float *fX, *fY;@\\
\mbox{}\verb@ int iNP;@\\
\mbox{}\verb@ char *name;@\\
\mbox{}\verb@ }UserData, *pUserData; @\\
\mbox{}\verb@/*---------------------------------------------------------------------*/@\\
\mbox{}\verb@ typedef struct __AMORSTAT {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ pICallBack pCall;@\\
\mbox{}\verb@ int iUserList;@\\
\mbox{}\verb@ pScanData pScan;@\\
\mbox{}\verb@ pHistMem pHM;@\\
\mbox{}\verb@ int iTOF;@\\
\mbox{}\verb@ }AmorStat, *pAmorStat;@\\
\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}
The fourth data structure is the amor status object data structure. It
has the following fields:
\begin{description}
\item[pDes] The standard SICS object descriptor.
\item[pCall] The callback interface.
\item[iUserList] A list of user data loaded data.
\item[pScan] A pointer to the scan object.
\item[pHM] A pointer to the histogram memory.
\item[iTOF] A flag which is true if we are taking measurements in TOF
mode.
\end{description}
In terms of a function interface this object has not much to
offer. Its main purpose is really as an interface to the status
display clients and thus it is configured through the interpreter
interface function. No need for other SICS objects to access it.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$asinter {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int AmorStatusFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int AmorStatusAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ void KillAmorStatus(void *pData);@\\
\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{scrap3}
\verb@"amorstat.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------@\\
\mbox{}\verb@ A M O R S T A T U S@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Internal data structure definitions for the AMOR status display @\\
\mbox{}\verb@ facilitator object. DO NOT CHANGE. This file is automatically@\\
\mbox{}\verb@ created from amorstat.w.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1999@\\
\mbox{}\verb@---------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$asdata {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@ @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
\verb@"amorstat.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------@\\
\mbox{}\verb@ A M O R S T A T U S@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Public definitions for the AMOR status display @\\
\mbox{}\verb@ facilitator object. DO NOT CHANGE. This file is automatically@\\
\mbox{}\verb@ created from amorstat.w.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1999@\\
\mbox{}\verb@---------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef AMORSTATUS@\\
\mbox{}\verb@#define AMORSTATUS@\\
\mbox{}\verb@@$\langle$asinter {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

102
amorstat.w Normal file
View File

@ -0,0 +1,102 @@
\subsection{Amor Status Display Support}
The reflectometer AMOR has a few unique status display requirements:
\begin{itemize}
\item In scan mode up to four detector counts curves must be shown for
the two counters in spin-up or spin-down mode. This needs to be
updated after each scan point.
\item Additionally user defined curves may need to be displayed.
\item The usual helper information muste be displayed.
\item In TOF mode it must be possible to define a region on the
detector whose summed counts are displayed versus the time
binning. This must be sent on request.
\end{itemize}
In order to cover all this a special object within SICS is required
which deals with all this and packages information in a status display
compliant way.
In order to do this the amorstatus object registers callbacks both
with the histogram memory and the scan object. These callback
functions are then responsible for updating the status displays. In
order for amorstatus to be able to do this, the client must register
itself with a special command.
In order to achieve all this some data structures are needed:
@d asdata @{
/*---------------------------------------------------------------------*/
typedef struct {
float *fX, *fY;
int iNP;
char *name;
}UserData, *pUserData;
/*---------------------------------------------------------------------*/
typedef struct __AMORSTAT {
pObjectDescriptor pDes;
pICallBack pCall;
int iUserList;
pScanData pScan;
pHistMem pHM;
int iTOF;
}AmorStat, *pAmorStat;
@}
The fourth data structure is the amor status object data structure. It
has the following fields:
\begin{description}
\item[pDes] The standard SICS object descriptor.
\item[pCall] The callback interface.
\item[iUserList] A list of user data loaded data.
\item[pScan] A pointer to the scan object.
\item[pHM] A pointer to the histogram memory.
\item[iTOF] A flag which is true if we are taking measurements in TOF
mode.
\end{description}
In terms of a function interface this object has not much to
offer. Its main purpose is really as an interface to the status
display clients and thus it is configured through the interpreter
interface function. No need for other SICS objects to access it.
@d asinter @{
int AmorStatusFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int AmorStatusAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
void KillAmorStatus(void *pData);
@}
@o amorstat.i @{
/*------------------------------------------------------------------------
A M O R S T A T U S
Internal data structure definitions for the AMOR status display
facilitator object. DO NOT CHANGE. This file is automatically
created from amorstat.w.
Mark Koennecke, September 1999
---------------------------------------------------------------------*/
@<asdata@>
@}
@o amorstat.h @{
/*------------------------------------------------------------------------
A M O R S T A T U S
Public definitions for the AMOR status display
facilitator object. DO NOT CHANGE. This file is automatically
created from amorstat.w.
Mark Koennecke, September 1999
---------------------------------------------------------------------*/
#ifndef AMORSTATUS
#define AMORSTATUS
@<asinter@>
#endif
@}

358
amortest.tcl Normal file
View File

@ -0,0 +1,358 @@
# --------------------------------------------------------------------------
# Initialization script for a simulated AMOR instrument
#
#
# Dr. Mark Koennecke September,1999 - ??, ????
#---------------------------------------------------------------------------
#------------ our home
set home /data/koenneck/src/sics
#----------- first all the server options are set
ServerOption ReadTimeOut 100
# timeout when checking for commands. In the main loop SICS checks for
# pending commands on each connection with the above timeout, has
# PERFORMANCE impact!
ServerOption AcceptTimeOut 100
# timeout when checking for connection req.
# Similar to above, but for connections
ServerOption ReadUserPasswdTimeout 7000
# time to wiat for a user/passwd to be sent from a client. Increase this
# if there is a problem connecting to a server due to network overload\
ServerOption LogFileDir $home/tmp
#LogFileDir is the directory where the command log is going
ServerOption LogFileBaseName $home/tmp/server
# the path and base name of the internal server logfile to which all
# activity will be logged.
ServerOption statusfile $home/tmp/sicsstatus.tcl
ServerOption ServerPort 2911
# the port number the server is going to listen at. The client MUST know
# this number in order to connect. It is in client.ini
ServerOption InterruptPort 2914
# The UDP port where the server will wait for Interrupts from clients.
# Obviously, clients wishing to interrupt need to know this number.
# Telnet options
ServerOption TelnetPort 1301
ServerOption TelWord sicslogin
ServerOption DefaultTclDirectory $home/tcl
ServerOption DefaultCommandFile topsicom.tcl
#------ a port for broadcasting UDP messages
ServerOption QuieckPort 2108
#---------------------------------------------------------------------------
# U S E R S
# than the SICS users are specified
# Syntax: SicsUser name password userRightsCode
SicsUser Mugger Diethelm 1
SicsUser User Rosy 2
SicsUser Spy 007 1
#--------------------------------------------------------------------------
# G E N E R A L V A R I A B L E S
# now a few general variables are created
# Syntax: VarMake name type access
# type can be one of: Text, Int, Float
#access can be one of: Internal, Mugger, user, Spy
VarMake Instrument Text Internal
Instrument AMOR
Instrument lock
VarMake Title Text User
VarMake sample Text User
sample "DanielSulfid"
Title "Amore mio in SINQ"
VarMake User Text User
User The reflective looser
VarMake lastscancommand Text User
VarMake Adress Text User
VarMake phone Text User
VarMake fax Text User
VarMake email Text User
VarMake sample_mur Float User
#--------------------------------------------------------------------------
# B u i l d i n g B l o c k s
#--------------------------------------------------------------------------
#
#=================== Chopper
VarMake chopperrotation Float User
chopperrotation 10000.
ClientPut "Starting motor initialization ....."
#=================== frame overlap mirror
VarMake fomname Text Mugger
fomname Super Duper Mirror
fomname lock
VarMake fomdist Float Mugger
fomdist 120
Motor FTZ SIM 0. 120. .1 2. # fom height
Motor FOM SIM -30. 30. .1 2. # fom omega
#================== first diaphragm
VarMake d1dist Float Mugger
d1dist 200.
Motor D1L SIM 0. 120. .1 2. # left
Motor D1R SIM 0. 120. .1 2. # right
Motor D1T SIM 0. 120. .1 2. # top
Motor D1B SIM 0. 1000. .1 2. # bottom
#================== polarizer
VarMake polname Text Mugger
polname Daniels Special Edition Polarizer
polname lock
VarMake poldist Float Mugger
fomdist 200
Motor MOZ SIM 0. 1000. .1 2. # pol table height
Motor MTY SIM -60. 60. .1 2. # pol y movement
Motor MOM SIM -30. 30. .1 2. # pol omega
Motor MTZ SIM -30. 30. .1 2. # pol omega height
#=================== diaphragm 2
VarMake d2dist Float Mugger
d2dist 200.
Motor D2L SIM 0. 120. .1 2. # left
Motor D2R SIM 0. 120. .1 2. # right
Motor D2T SIM 0. 120. .1 2. # top
Motor D2B SIM 0. 1000. .1 2. # bottom
#==================== diaphragm 3
VarMake d3dist Float Mugger
d3dist 200.
Motor D3L SIM 0. 120. .1 2. # left
Motor D3R SIM 0. 120. .1 2. # right
Motor D3T SIM 0. 120. .1 2. # top
Motor D3B SIM 0. 1000. .1 2. # bottom
#===================== sample table
VarMake sampledist Float Mugger
sampledist 200
Motor STZ SIM -50. 50. .1 2. # sample height
Motor SOM SIM -30. 30. .1 2. # sample omega
Motor SCH SIM -30. 30. .1 2. # sample chi
Motor SOZ SIM 0. 1000. .1 2. # table height
#====================== diaphragm 4
VarMake d4dist Float Mugger
d4dist 200.
Motor D4L SIM 0. 120. .1 2. # left
Motor D4R SIM 0. 120. .1 2. # right
Motor D4T SIM 0. 120. .1 2. # top
Motor D4B SIM 0. 1000. .1 2. # bottom
#======================= analyzer
VarMake ananame Text Mugger
ananame Daniels Special Edition Analyzer
ananame lock
VarMake anadist Float Mugger
anadist 200
Motor AOZ SIM 0. 1000. .1 2. # analyzer table height
Motor AOM SIM -30. 30. .1 2. # analyzer omega
Motor ATZ SIM -30. 30. .1 2. # analyzer omega height
#======================== diaphragm 5
VarMake d5dist Float Mugger
d5dist 200.
Motor D5L SIM 0. 120. .1 2. # left
Motor D5R SIM 0. 120. .1 2. # right
Motor D5T SIM 0. 120. .1 2. # top
Motor D5B SIM 0. 1000. .1 2. # bottom
#======================== counter
VarMake detectordist Float Mugger
detectordist 200.
MakeCounter counter SIM .0001
Motor COZ SIM 0. 1000. .1 2. # counter table height
Motor C3Z SIM 0. 300. .1 2. # counter height
Motor COM SIM -30. 30. .1 2. # counter omega
Motor COX SIM -100. 100. .1 2. # counter x
ClientPut "Motors initialized"
#======================== histogram memory
#MakeHM hm SinqHM
MakeHM hm SIM
hm configure OverFlowMode Ceil
hm configure HistMode PSD
hm configure Rank 2
hm configure dim0 128
hm configure dim1 256
hm configure xfac 10
hm configure yfac 10
hm configure xoff 64
hm configure yoff 128
hm configure BinWidth 4
hm preset 100.
hm CountMode Timer
hm configure HMComputer psds03.psi.ch
hm configure HMPort 2400
hm configure Counter counter
hm configure init 0
hm genbin 0. 33 5
hm init
ClientPut "Histogram Memory Initialized"
#--------------------------------------------------------------------------
# D a t a S t o r a g e
#------------------------------------------------------------------------
VarMake SicsDataPath Text Mugger
SicsDataPath $home/
SicsDataPath lock
VarMake SicsDataPrefix Text Mugger
SicsDataPrefix amortest
SicsDataPrefix lock
VarMake SicsDataPostFix Text Mugger
SicsDataPostFix ".hdf"
SicsDataPostFix lock
MakeDataNumber SicsDataNumber $home/danu.dat
#--------------------------------------------------------------------------
# C o m m a n d I n i t i a l i z a t i o n
#-------------------------------------------------------------------------
#======== Drive
MakeDrive
#======== scan
source $home/object.tcl
source $home/tcl/scancom.tcl
MakeScanCommand xxxscan counter topsi.hdd recover.bin
xxxscan configure amor
#========== peak & center
MakePeakCenter xxxscan
source /data/koenneck/src/sics/countf.tcl
#========== serial port general purpose
SerialInit
Publish serialport User
Publish p1 User
#=========== the optimiser
MakeOptimise opti counter
#=========== Amor2T
set a2t(mom) mom
set a2t(som) som
set a2t(coz) coz
set a2t(cox) cox
set a2t(stz) stz
set a2t(soz) soz
set a2t(d4b) d4b
set a2t(d5b) d5b
set a2t(com) com
set a2t(aom) aom
set a2t(aoz) aoz
set a2t(c3z) c3z
MakeAmor2T a2t a2t aom2t
MakeStoreAmor hm a2t
#=========== Status Display Support
MakeAmorStatus amorstatus xxxscan hm
source amorpar.tcl
Publish amorpar Spy
ClientPut "Done Initializing"
scriptcallback connect xxxscan SCANSTART scanmode
scriptcallback connect hm COUNTSTART tofmode
sicsdatafactory new wwwdata
Publish getmode Spy
Publish wwwgetdata Spy
Publish wwwsics Spy
Publish wwwgetaxis Spy
#-----------------------------------------------------------------
set mode 0
proc tofmode {} {
global mode
set mode 1
}
#---------------------------------------------------------------------
proc scanmode {} {
global mode
set mode 0
}
#------------------------------------------------------------------
proc getmode {} {
global mode
return $mode
}
#--------------------------------------------------------------------
proc wwwgetdata {} {
global mode
if {$mode == 1} {
wwwtofdata
} else {
wwwscandata
}
wwwdata writeuu wwwdata
}
#---------------------------------------------------------------------
proc wwwscandata {} {
wwwdata clear
set np [string trim [SplitReply [xxxscan np]]]
wwwdata putint 0 $np
if {$np > 0} {
wwwdata copyscanvar 1 xxxscan 0
wwwdata copyscancounts [expr $np + 1] xxxscan
wwwdata copyscanmon [expr $np*2 + 1] xxxscan 2
}
}
#----------------------------------------------------------------------
proc wwwtofdata {} {
wwwdata clear
set ntime [string trim [SplitReply [hm notimebin]]]
set dim0 [string trim [SplitReply [hm configure dim0]]]
set dim1 [string trim [SplitReply [hm configure dim1]]]
wwwdata putint 0 $ntime
wwwdata copytimebin 1 hm
set start [expr $dim0*$dim1*$ntime]
set end [expr $start + 2*$ntime]
wwwdata copyhm [expr $ntime + 1] hm $start $end
}
#---------------------------------------------------------------------------
proc wwwsics {} {
global mode
append result "<table BORDER=2>\n"
append result "<tr><th>User</th> <td>" [SplitReply [user]] "</td></tr>\n"
append result "<tr><th>Title</th> <td>"
append result [SplitReply [title]] "</td></tr>\n"
append result "<tr><th>Status</th> <td>"
append result [SplitReply [status]] "</td></tr>\n"
append result "<tr><th>Mode</th><td>"
if {$mode == 1} {
append result "time-of-flight"
} else {
append result "scan mode"
}
append result "</td></tr>\n"
append result "</table>\n"
}
#-------------------------------------------------------------------------
proc wwwgetaxis {} {
global mode
if {$mode == 1} {
return time-of-flight
} else {
set res [scan info]
set l [split $res ,]
return [lindex $l 2]
}
}

374
anticollider.c Normal file
View File

@ -0,0 +1,374 @@
/*----------------------------------------------------------------------
This is the implementation file for the AntiCollider, a complex movements
control module for SICS. See anticollider.tex for more information.
copyright: see file copyright
Mark Koennecke, August 2002
------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <tcl.h>
#include "fortify.h"
#include "lld.h"
#include "motreglist.h"
#include "anticollider.i"
#include "anticollider.h"
/*---------------------------------------------------------------------
As there should be only one AntiCollider in a system, I use a static
pointer to the AntiCollider here in order to facilitate access.
Otherwise more complex mechanisms must be devised in order to pass this
pointer into ColliderSetValue and ColliderCheckStatus
----------------------------------------------------------------------*/
static pAntiCollider myCollider = NULL;
/*--------------------------------------------------------------------
the replacement function for the motor's drivable interface SetValue
function. It enters the new target into the motor list.
---------------------------------------------------------------------*/
static long ReplacementSetValue(void *pData, SConnection *pCon, float fTarget){
pMotReg pMot = NULL;
assert(myCollider != NULL);
pMot = FindMotFromDataStructure(myCollider->motorList,pData);
if(pMot != NULL){
SetRegMotTarget(pMot,fTarget);
myCollider->isDirty = 1;
} else {
return 0;
}
return 1;
}
/*---------------------------------------------------------------------
The replacement CheckStatus function for controlled motors.
Start AntiCollider if not running and finish. Rest of work done by
AntiCollider.
-----------------------------------------------------------------------*/
static int ReplacementCheckStatus(void *pData, SConnection *pCon){
pMotReg pMot = NULL;
assert(myCollider != NULL);
if(myCollider->isDirty == 1){
myCollider->isDirty = 0;
StartDevice(pServ->pExecutor,
"anticollider",
myCollider->pDes,
myCollider,
pCon,
77.77);
return HWIdle;
} else {
return HWIdle;
}
}
/*------------------------------------------------------------------------
The collider SetValue function
-------------------------------------------------------------------------*/
static long ColliderSetValue(void *pData, SConnection *pCon, float fTarget){
pAntiCollider self = (pAntiCollider) pData;
int iRet;
pMotReg pMot = NULL;
char pBueffel[80];
char *ruenBuffer = NULL;
Tcl_DString command;
/*
build command list
*/
if(self->colliderScript == NULL){
SCWrite(pCon,"ERROR: no collider script defined",eError);
return 0;
}
Tcl_DStringInit(&command);
Tcl_DStringAppend(&command,self->colliderScript,-1);
iRet = LLDnodePtr2First(self->motorList);
while(iRet != 0){
LLDnodeDataTo(self->motorList,&pMot);
if(pMot != NULL){
if(pMot->iActive){
CreateTargetString(pMot,pBueffel);
Tcl_DStringAppend(&command, pBueffel,-1);
pMot->iActive = 0;
}
}
iRet = LLDnodePtr2Next(self->motorList);
}
/*
kill old collider sequence
*/
LLDdelete(self->sequenceList);
self->sequenceList = LLDcreate(sizeof(Sequence));
self->level = -1; /* otherwise level 0 will not be started */
/*
evaluate colliderScript
*/
iRet = Tcl_Eval(pServ->pSics->pTcl,Tcl_DStringValue(&command));
if(iRet != TCL_OK){
SCWrite(pCon,"ERROR: Movement not possible or bad collider script",eError);
/*
SCWrite(pCon,pServ->pSics->pTcl->result,eError);
*/
SCSetInterrupt(pCon,eAbortOperation);
return 0;
}
/*
we are set
*/
Tcl_DStringFree(&command);
return 1;
}
/*----------------------------------------------------------------------
The Collider CheckStatus function
-----------------------------------------------------------------------*/
static int ColliderCheckStatus(void *pData, SConnection *pCon){
int count = 0;
pAntiCollider self = (pAntiCollider) pData;
assert(self);
if(SCGetInterrupt(pCon) != eContinue){
return HWIdle;
}
count = CheckAllMotors(self->motorList,pCon);
if(count == 0){
self->level++;
count = StartLevel(self->level,
self->sequenceList,
self->motorList,
pCon);
if(count == 0){
/*
no more levels. All done
*/
return HWIdle;
} else {
return HWBusy;
}
} else {
return HWBusy;
}
}
/*----------------------------------------------------------------------
Most of these are dummies........
-----------------------------------------------------------------------*/
static int ColliderHalt(void *pData){
StopExe(pServ->pExecutor,"all");
return 1;
}
/*---------------------------------------------------------------------*/
static int ColliderLimits(void *self, float fVal, char *error,
int iErren){
return 1;
}
/*--------------------------------------------------------------------*/
static float ColliderGetValue(void *self, SConnection *pCon){
return 77.77;
}
/*--------------------------------------------------------------------*/
int StartLevel(int level, int sequenceList, int motorList, SConnection *pCon){
Sequence seq;
pMotReg pMot = NULL;
int iRet;
int count = 0;
char pBueffel[132];
iRet = LLDnodePtr2First(sequenceList);
while(iRet != 0){
LLDnodeDataTo(sequenceList,&seq);
if(seq.level == level){
pMot = FindMotEntry(motorList,seq.pMotor);
if(pMot){
StartRegMot(pMot,pCon,seq.target);
count++;
} else {
sprintf(pBueffel,"ERROR: motor %s, requested from anticollider script",
seq.pMotor);
SCWrite(pCon,pBueffel,eError);
SCWrite(pCon,"ERROR: motor NOT found, fix script!",eError);
}
}
iRet = LLDnodePtr2Next(sequenceList);
}
return count;
}
/*--------------------------------------------------------------------*/
static void ListSequence(int sequenceList, SConnection *pCon){
Sequence seq;
int iRet;
char pBueffel[132];
SCWrite(pCon,"level motor target",eValue);
iRet = LLDnodePtr2First(sequenceList);
while(iRet != 0){
LLDnodeDataTo(sequenceList,&seq);
sprintf(pBueffel,"%d %s %f",seq.level,seq.pMotor,seq.target);
SCWrite(pCon,pBueffel,eValue);
iRet = LLDnodePtr2Next(sequenceList);
}
}
/*-------------------------------------------------------------------------*/
static void *ColliderGetInterface(void *pData, int iID) {
pAntiCollider self = NULL;
self = (pAntiCollider)pData;
assert(self);
if(iID == DRIVEID){
return self->pDriv;
}
return NULL;
}
/*----------------------------------------------------------------------*/
void KillCollider(void *pData){
pAntiCollider self = (pAntiCollider)pData;
if(self == NULL){
return;
}
if(self->pDes != NULL){
DeleteDescriptor(self->pDes);
}
if(self->pDriv != NULL){
free(self->pDriv);
}
if(self->colliderScript != NULL){
free(self->colliderScript);
}
if(self->motorList > 0){
KillMotList(self->motorList);
}
if(self->sequenceList > 0){
LLDdelete(self->sequenceList);
}
free(self);
myCollider = NULL;
}
/*-----------------------------------------------------------------------*/
int AntiColliderFactory(SConnection *pCon, SicsInterp *pSics,
void *pData,
int argc, char *argv[]){
myCollider = (pAntiCollider)malloc(sizeof(AntiCollider));
if(myCollider == NULL){
SCWrite(pCon,"ERROR: out of memory when generating AntiCollider",eError);
return 0;
}
memset(myCollider,0,sizeof(AntiCollider));
myCollider->pDes = CreateDescriptor("AntiCollider");
myCollider->pDriv = CreateDrivableInterface();
if(!myCollider->pDes || !myCollider->pDriv){
KillCollider(myCollider);
SCWrite(pCon,"ERROR: out of memory when generating AntiCollider",eError);
return 0;
}
myCollider->pDes->GetInterface = ColliderGetInterface;
myCollider->pDriv->Halt = ColliderHalt;
myCollider->pDriv->CheckLimits = ColliderLimits;
myCollider->pDriv->SetValue = ColliderSetValue;
myCollider->pDriv->CheckStatus = ColliderCheckStatus;
myCollider->pDriv->GetValue = ColliderGetValue;
myCollider->motorList = LLDcreate(sizeof(void *));
myCollider->sequenceList = LLDcreate(sizeof(Sequence));
AddCommand(pSics,"anticollision",AntiColliderAction,
KillCollider,
myCollider);
return 1;
}
/*------------------------------------------------------------------------*/
int AntiColliderAction(SConnection *pCon, SicsInterp *pSics,
void *pData,
int argc, char *argv[]){
pAntiCollider self = (pAntiCollider)pData;
Sequence seq;
char pBueffel[256];
pMotReg pMot = NULL;
assert(self != NULL);
if(argc > 1){
if(strcmp(argv[1],"clear") == 0){
if(!SCMatchRights(pCon,usUser)){
return 0;
}
LLDdelete(self->sequenceList);
self->sequenceList = LLDcreate(sizeof(Sequence));
SCSendOK(pCon);
return 1;
} else if(strcmp(argv[1],"list") == 0){
ListSequence(self->sequenceList,pCon);
return 1;
}
}
if(argc < 3){
SCWrite(pCon,"ERROR : insufficient number of arguments to anticollision",
eError);
return 0;
}
strtolower(argv[1]);
if(strcmp(argv[1],"script") == 0){
if(!SCMatchRights(pCon,usMugger)){
return 0;
}
if(self->colliderScript != NULL){
free(self->colliderScript);
}
self->colliderScript = strdup(argv[2]);
SCSendOK(pCon);
return 1;
} else if(strcmp(argv[1],"register") == 0){
if(!SCMatchRights(pCon,usMugger)){
return 0;
}
if(FindDrivable(pSics,argv[2]) == NULL){
sprintf(pBueffel,"ERROR: %s is NOT drivable, cannot register",argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
pMot = RegisterMotor(argv[2],pSics,
ReplacementSetValue,
ReplacementCheckStatus);
if(pMot){
LLDnodeAppendFrom(self->motorList,&pMot);
SCSendOK(pCon);
return 1;
} else {
SCWrite(pCon,"ERROR: out of memory registering motor",eError);
return 0;
}
} else if(strcmp(argv[1],"add") == 0){
if(argc < 5){
SCWrite(pCon,
"ERROR: InsUfficient number of arguments to anticollicion add",
eError);
return 0;
}
seq.level = atoi(argv[2]);
strncpy(seq.pMotor,argv[3],79);
seq.target = atof(argv[4]);
LLDnodeAppendFrom(self->sequenceList,&seq);
SCSendOK(pCon);
return 1;
}
SCWrite(pCon,"ERROR: anticollider command not understood",eError);
return 0;
}

25
anticollider.h Normal file
View File

@ -0,0 +1,25 @@
/*----------------------------------------------------------------------
This is the header file for the AntiCollider, a complex movements
control module for SICS. See anticoliider.tex for more information.
copyright: see file copyright
Mark Koennecke, August 2002
------------------------------------------------------------------------*/
#ifndef ANTICOLLIDER
#define ANTICOLLIDER
int AntiColliderFactory(SConnection *pCon, SicsInterp *pSics,
void *pData,
int argc, char *argv[]);
int AntiColliderAction(SConnection *pCon, SicsInterp *pSics,
void *pData,
int argc, char *argv[]);
#endif

28
anticollider.i Normal file
View File

@ -0,0 +1,28 @@
/*-------------------------------------------------------------------------
Anticollider internal data structure definition. Generated from
anticollider.w. Do not edit.
-------------------------------------------------------------------------*/
typedef struct __ANTICOLLIDER{
pObjectDescriptor pDes;
pIDrivable pDriv;
int motorList;
int sequenceList;
char *colliderScript;
int isDirty;
int level;
}AntiCollider, *pAntiCollider;
typedef struct {
int level;
char pMotor[80];
float target;
}Sequence;
int StartLevel(int level, int sequenceList, int motorList,
SConnection *pCon);

275
anticollider.w Normal file
View File

@ -0,0 +1,275 @@
\subsubsection{The Anti Collider}
In some cases certain instrument positions can only be reached through
special sequences of drive instructions. Usually because some concrete
blocks or unduly bulky sample environment devices are in the path of
the instrument. Such cases can not be handled through primitive motor
limits. Handling such cases is the objective of the Anti Collider.
The first thing needed is that motors involved with such complex
movements are registered with the Anti Collider. In this stage the
Anti Collider will take over the SetValue and CheckStatus functions of
the drivable interface of the motor. SetValue will be replaced by a
function which will register the drive request with the Anti
Collider. CheckStatus will be replaced by a version which checks with
the Anti Collider if the complex movement has finished.
It is expected that coordinated and complex movements are initiated
within a single command. The first checkpoint where the complex
movement can be analyzed and coordinated the is when the device
executor calls CheckStatus for the first time. CheckStatus will detect
this condition and proceeds to call a Tcl procedure which then has to
create a r\"unb\"uffer which holds the necessary commands to drive the
complex movement. Or returns an error if the movement is not
possible. This scheme allows the instrument scientist to adapt the
way how the instrument moves to new sample environment devices, new
ideas or the growth of experience. Moreover this scheme allows to
handle all instruments with just a single module. As the Anti Collider
has taken over the SetValue method of the drivable interface of the
motor a command is provided which allows to start the actual motor.
The user supplied Tcl script receives as arguments a list of motor and
target values to be driven. The script then has to return either an
error if the movement is not possible or the name of a r\"unb\"uffer
which performs the movement.
The first thing needed for all this is a data structure which holds
the registration information and status of the controlled motor. This
information will be kept in a list holding the data tsrucutre given
below:
@d motreg @{
typedef struct __MOTREG {
void *motorData;
char *motorName;
float targetPosition;
long (*originalSetValue)(void *motorData,
SConnection *pCon,
float fTarget);
int (*originalCheckStatus)(void *motorData,
SConnection *pCon);
int iActive;
} MotReg, *pMotReg;
@}
The fields are:
\begin{description}
\item[motorData] The motor data structure.
\item[motorName] The name of the motor operating.
\item[targetPosition] The requested target position for this motor.
\item[originalSetValue] the original motor starting function.
\item[originalCheckStatus] The original status checking function.
\item[iActive] A flag denoting if the motor has been started by the
Anti Collider. This causes the motors status to be checked which
checking status. If the motor becomes idle, this is set to 0 again.
\end{description}
The following interface functions are defined for this datastructure:
@d motregint @{
pMotReg RegisterMotor(char *name, SicsInterp *pSics,
long (*SetValue)(void *pData, SConnection *pCon, float
fTarget),
int (*CheckStatus)(void *pData, SConnection *pCon));
void KillRegMot(void *self);
void SetRegMotTarget(pMotReg self, float target);
void CreateTargetString(pMotReg self, char pBueffel[80]);
int RegMotMatch(pMotReg self, char *name);
int StartRegMot(pMotReg self, SConnection *pCon, float fValue);
int CheckRegMot(pMotReg self, SConnection *pCon);
@}
The functions in detail:
\begin{description}
\item[RegisterMotor] tries to find the motor name in the interpreter
pSics. Then all necessary manipulations are performed in order to
register the motor. In ths case of success a pointer to a new RegMot
data structure is returned. In the event of failure, NULL is
returned. Of course this function has to take the function pointers to
the drivable interface functions to replace as parameters.
\item[KillRegMot] kills a RegMot structure.
\item[SetRegMotTarget] sets a new target for a complex movement.
\item[CreateTragetString] creates in pBueffel this motors contribution
to a complex movement.
\item[RegMotMatch] returns 1 (true) if the string name matches the name stored
for this motor. Else 0. This will be used when searching for a
registered motor in the list.
\item[StartRegMot] will actually cause a real motor to start driving
towards the target given in fValue. The return value is the result of
the original motors SetValue method.
\item[CheckRegMot] checks for error conditions on the motor.
\end{description}
Moreover it is convenient to define a couple of convenience functions
for handling the list of registered motors. The actual list is
managed through the lld functions as everywhere within SICS.
@d motlist @{
int MakeMotList();
pMotReg FindMotEntry(int iList,char *name);
pMotReg FindMotFromDataStructure(int iList, void *pData);
int CheckAllMotors(int iList, SConnection *pCon);
void KillMotList(int iList);
@}
The functions:
\begin{description}
\item[MakeMotList] creates a new list for MotReg structures and
returns the handle for it.
\item[FindMotEntry] locates a motor in the list by name. If a matching
motor can be found, this function returns a pointer to the motors
MotReg structure. In the case of failure NULL is returned.
\item[FindMotFromDataStructure] locates a motor in the list through
the pointer to its data structure. . If a matching
motor can be found, this function returns a pointer to the motors
MotReg structure. In the case of failure NULL is returned.
\item[CheckAllMotors] checks all the active motors for the finished
condition. The number of running motors is returned. 0 if none is running.
\item[KillMotList] kills the list and all entries in it.
\end{description}
In order to know how the anticollider has to run the motors a means is
needed to hold the sequence of motors to drive. This information must
be configured from the anticollider script. The information is held in
another list in a special data structure.
@d seqlist @{
typedef struct {
int level;
char pMotor[80];
float target;
}Sequence;
int StartLevel(int level, int sequenceList, int motorList,
SConnection *pCon);
@}
The fields and functions are:
\begin{description}
\item[level] The level at which this motor shall be started.
\item[pMotor] The name of the motor to start.
\item[target] The target value for the motor.
\item[StartLevel] starts all motors belonging to a the level
specified. Returns the number of motors started or ) if none is
started. This last condition is also the condition when levels are
exhausted and we need to finish running the anticollider.
\end{description}
The anticollider itself is characterized through the following data
structure:
@d antidat @{
typedef struct __ANTICOLLIDER{
pObjectDescriptor pDes;
pIDrivable pDriv;
int motorList;
int sequenceList;
char *colliderScript;
int isDirty;
int level;
}AntiCollider, *pAntiCollider;
@}
The fields are:
\begin{description}
\item[pDes] The object descriptor required by SICS.
\item[motorList] The list of registered motors.
\item[colliderScript] the Tcl script called to calculate the movement.
\item[iDirty] a flag which is set to 1 (true) when a new movement must
be calculated.
\end{description}
Most of the anticolliders functionality is implemented in interface
functions. The interface to the outside world is purely defined
through the interpreter functions.
@d antiint @{
int AntiColliderFactory(SConnection *pCon, SicsInterp *pSics,
void *pData,
int argc, char *argv[]);
int AntiColliderAction(SConnection *pCon, SicsInterp *pSics,
void *pData,
int argc, char *argv[]);
@}
@o motreg.h @{
/*-------------------------------------------------------------------------
R e g M o t
This is a helper module for the Anti Collider. It handles all the
stuff necessary for dealing with a single motor. For more
information see the file anticollider.tex.
copyright: see file copyright
Mark Koennecke, August 2002
-----------------------------------------------------------------------*/
#ifndef REGMOT
#define REGMOT
#include "sics.h"
@<motreg@>
/*----------------------------------------------------------------------*/
@<motregint@>
#endif
@}
@o motreglist.h @{
/*-----------------------------------------------------------------------
A couple of utility functions for handling a list of MotReg
structures . This is a helper module for the anticollider collision
control system. See anticollider.tex for more details.
copyright: see file copyright
Mark Koennecke, August 2002
-------------------------------------------------------------------------*/
#ifndef MOTREGLIST
#define MOTREGLIST
#include "motreg.h"
@<motlist@>
#endif
@}
@o anticollider.i @{
/*-------------------------------------------------------------------------
Anticollider internal data structure definition. Generated from
anticollider.w. Do not edit.
-------------------------------------------------------------------------*/
@<antidat@>
@<seqlist@>
@}
@o anticollider.h @{
/*----------------------------------------------------------------------
This is the header file for the AntiCollider, a complex movements
control module for SICS. See anticoliider.tex for more information.
copyright: see file copyright
Mark Koennecke, August 2002
------------------------------------------------------------------------*/
#ifndef ANTICOLLIDER
#define ANTICOLLIDER
@<antiint@>
#endif
@}

7
ati.tcl Normal file
View File

@ -0,0 +1,7 @@
drive mom 3.
scan var a2t 0. .2
scan var som 0. .1
scan preset 1
scan mode timer
scan np 20
scan run

46
author.txt Normal file
View File

@ -0,0 +1,46 @@
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <tcl.h>
#include "fortify.h"
#include "lld.h"
#include "lld_blob.h"
#include "lld_str.h"
#include "conman.h"
#include "obdes.h"
#include "fupa.h"
#include "motor.h"
#include "datadmc.h"
#include "countdriv.h"
#include "counter.h"

211
autofile.tcl Normal file
View File

@ -0,0 +1,211 @@
#----------------------------------------------------------------------------
# This is part of the WWW-interface to SICS. This interface allows to
# create batch files to be run automatically by SICS. These files are
# stored in a special directory as files with the ending .sip by the
# CGI-scripts or servlets creating them. Now, a system is needed which
# checks this directory regularly for new files and executes them in SICS.
# This is the purpose of the SICS-Tcl macros defined in this file.
#
# First edition: Mark Koennecke, December 1999
#----------------------------------------------------------------------------
#----------- !!!! the path where the automatic files reside
set autofpath "/data/koenneck/tmp/auto"
#------- a variable which defines if we should operate and the current file.
set __autofile_run 0
set __auto_exe_file ""
#!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# There is a name command between the Tcl internal scan command and the
# SICS scan command. The Tcl internal has to be renamed. The following
# variable defines the name of the Tcl scan command
set tclscan stscan
#---------- do initializing things when called first time
set ret [catch [catch {autofile} msg]
if {$ret != 0} {
VarMake autofilepath Text Mugger
autofilepath $autofpath
autofilepath lock
Publish autofileexecute User
Publish autofile Mugger
Publish autostart User
Publish autoadd User
Publish autoend User
#------- for automatic file name creation
catch {MakeDataNumber autonumber $autofpath/autonumber.dat}
#------- check any 30 seconds
sicscron 30 autofileexecute
}
#--------------------------------------------------------------------------
proc autofile { {action null} } {
upvar #0 __autofile_run ar
if { [string compare $action start] == 0} {
set ar 1
return OK
} elseif { [string compare $action stop] == 0 } {
set ar 0
return OK
} else {
if {$ar == 1} {
return on
} else {
return off
}
}
}
#--------------------------------------------------------------------------
proc autofileexecute { } {
upvar #0 __autofile_run ar
upvar #0 __auto_exe_file aef
upvar #0 tclscan filescan
#--------- no operation if not activated
if {$ar != 1} {
return
}
#--------- aquire a list of candidate batch files
set tmp [autofilepath]
set ltmp [split $tmp =]
set tmp [lindex $ltmp 1]
set tmp2 [string trim $tmp]/*.inp
set ret [catch {set filelist [glob $tmp2]} msg]
if {$ret != 0} {
return "Nothing to do"
}
if { [llength $filelist] < 1 } {
return "Nothing to do"
}
#--------- now, in each file the second line contains the order number,
# find the lowest one which is the next one to execute
set minnum 999999
set file2exe null
foreach fil $filelist {
set f [open $fil r]
gets $f
set numline [gets $f]
set ret [catch {$filescan $numline "# %d" numi} msg]
close $f
if { $ret == 0 } {
if { $numi < $minnum } {
set minnum $numi
set file2exe $fil
}
} else {
ClientPut $msg
}
}
#------------ having found an input file, execute it
if { [string compare $file2exe null] != 0 } {
set aef $file2exe
set ret [catch {interneval $file2exe} msg]
#------ after execution rename it with a different extension
set fil2 [file rootname $file2exe].old
file rename -force $file2exe $fil2
if {$ret != 0 } {
error $msg
} else {
return $msg
}
}
return "Invalid autobatch files"
}
#=========================================================================
# File management functions
#
# autostart creates a fresh file. The data is stored in a SICS runbuffer.
# autoadd adds a line to the runbuffer
# autoend writes the file to disk then.
#=========================================================================
proc autostart {} {
catch {buf del autobuffer}
Buf new autobuffer
}
proc autoadd args {
autobuffer append $args
}
proc autoend {} {
upvar #0 autofpath ap
autonumber incr
set txt [autonumber]
set l [split $txt =]
set txt [string trim [lindex $l 1]]
set fil [format "$ap/auto%7.7d.inp" $txt]
set filnum [format "# %d" $txt]
autobuffer ins 1 $filnum
autobuffer save $fil
Buf del autobuffer
}
#============================================================================
# file list management
#============================================================================
proc buildsortedlist {filar} {
upvar #0 autofpath ap
upvar $filar list
set i 0
#----------- build arrays of all relevant files
set ret [catch {set l1 [glob $ap/*.inp]}]
if { $ret == 0 } {
foreach fil $l1 {
set list($i)
incr i
set f [open $fil r]
set $fil(title) [gets $f]
set txt [gets $f]
close $f
set ret [catch {$filescan $txt "# %d" numi} msg]
if { $ret == 0} {
set fil(no) $numi
}else {
set fil(no) -10
}
}
}
set ret [catch {set l1 [glob $ap/*.old]}]
if { $ret == 0 } {
foreach fil $l1 {
set list($i)
incr i
set f [open $fil r]
set $fil(title) [gets $f]
set txt [gets $f]
close $f
set ret [catch {$filescan $txt "# %d" numi} msg]
if { $ret == 0} {
set fil(no) $numi
}else {
set fil(no) -10
}
}
}
set nfil i
#--------- now selection sort this list
for {set i 0} { i < $nfil} {incr i} {
set min $i
set ff $list($min)
for {set j [expr $i + 1]} {$j < $nfil} {incr j} {
set ff $list($j)
set fff $list($min)
if { $ff(no) < $fff(no)} {
set min $j
}
}
set t $list($min)
set list($min) $list($min)
set list($i) $t
}
}
proc autolist {} {
}

137
backup.tcl Normal file
View File

@ -0,0 +1,137 @@
# RuenBuffer Renate
Buf new Renate
Renate append Alle Fische sind schon da
Renate append Alle Nixen auch
Renate append Nur die dummen Neutronen kommen nicht
Renate append Und die Schluempfe kriegen es auch nicht gebacken
# RuenBuffer Kunigunde
Buf new Kunigunde
Kunigunde append Alle Fische sind schon da
Kunigunde append Alle Nixen auch
Kunigunde append Nur die dummen Neutronen kommen nicht
Kunigunde append Und die Schluempfe kriegen es auch nicht gebacken
# RuenBuffer Walter
Buf new Walter
Walter append Alle Fische sind schon da
Walter append Alle Nixen auch
Walter append Nur die dummen Neutronen kommen nicht
Walter append Und die Schluempfe kriegen es auch nicht gebacken
# RuenBuffer Willi
Buf new Willi
Willi append Alle Nixen auch
Willi append Und die Schluempfe kriegen es auch nicht gebacken
# RuenBuffer Heinz
Buf new Heinz
Heinz append GGG Fische sind schon da
Heinz append GGG Nixen auch
Heinz append Nur die dummen Neutronen kommen schon
Heinz append Und die Schluempfe kriegen es auch schon gebacken
Curve SoftLowerLim 0.000000
Curve SoftUpperLim 1000.000000
Curve SoftZero 0.000000
Curve Fixed -1.000000
Curve InterruptMode 0.000000
Curve AccessCode 2.000000
TwoTheta SoftLowerLim -140.000000
TwoTheta SoftUpperLim 140.000000
TwoTheta SoftZero 0.000000
TwoTheta Fixed -1.000000
TwoTheta InterruptMode 0.000000
TwoTheta AccessCode 2.000000
Theta SoftLowerLim -70.000000
Theta SoftUpperLim 70.000000
Theta SoftZero 0.000000
Theta Fixed -1.000000
Theta InterruptMode 0.000000
Theta AccessCode 2.000000
bsy SoftLowerLim -50.000000
bsy SoftUpperLim 50.000000
bsy SoftZero 0.000000
bsy Fixed -1.000000
bsy InterruptMode 0.000000
bsy AccessCode 2.000000
bsx SoftLowerLim -50.000000
bsx SoftUpperLim 50.000000
bsx SoftZero 0.000000
bsx Fixed -1.000000
bsx InterruptMode 0.000000
bsx AccessCode 2.000000
dphi SoftLowerLim 0.000000
dphi SoftUpperLim 360.000000
dphi SoftZero 0.000000
dphi Fixed -1.000000
dphi InterruptMode 0.000000
dphi AccessCode 2.000000
dsy SoftLowerLim -50.000000
dsy SoftUpperLim 50.000000
dsy SoftZero 0.000000
dsy Fixed -1.000000
dsy InterruptMode 0.000000
dsy AccessCode 2.000000
dsd SoftLowerLim 0.000000
dsd SoftUpperLim 18000.000000
dsd SoftZero 0.000000
dsd Fixed -1.000000
dsd InterruptMode 0.000000
dsd AccessCode 2.000000
saz SoftLowerLim 0.000000
saz SoftUpperLim 30.000000
saz SoftZero 0.000000
saz Fixed -1.000000
saz InterruptMode 0.000000
saz AccessCode 2.000000
say SoftLowerLim -22.000000
say SoftUpperLim 22.000000
say SoftZero 0.000000
say Fixed -1.000000
say InterruptMode 0.000000
say AccessCode 2.000000
sax SoftLowerLim -30.000000
sax SoftUpperLim 30.000000
sax SoftZero 0.000000
sax Fixed -1.000000
sax InterruptMode 0.000000
sax AccessCode 2.000000
som SoftLowerLim -180.000000
som SoftUpperLim 360.000000
som SoftZero 0.000000
som Fixed -1.000000
som InterruptMode 0.000000
som AccessCode 2.000000
sphi SoftLowerLim -22.000000
sphi SoftUpperLim 22.000000
sphi SoftZero 0.000000
sphi Fixed -1.000000
sphi InterruptMode 0.000000
sphi AccessCode 2.000000
schi SoftLowerLim -22.000000
schi SoftUpperLim 22.000000
schi SoftZero 0.000000
schi Fixed -1.000000
schi InterruptMode 0.000000
schi AccessCode 2.000000
comment (null)
comment setAccess 2
environment (null)
environment setAccess 2
SubTitle (null)
SubTitle setAccess 2
User set
User setAccess 2
Title Alle meine Entchen sind schon da
Title setAccess 2
Instrument set
Instrument setAccess 0

47
bare.tcl Normal file
View File

@ -0,0 +1,47 @@
# --------------------------------------------------------------------------
# Initialization script for a simulated TOPSI instrument
#
#
# Dr. Mark Koennecke February, 1996
#---------------------------------------------------------------------------
# O P T I O N S
# --------------- Initialize Tcl internals --------------------------------
# first all the server options are set
ServerOption ReadTimeOut 10
# timeout when checking for commands. In the main loop SICS checks for
# pending commands on each connection with the above timeout, has
# PERFORMANCE impact!
ServerOption AcceptTimeOut 10
# timeout when checking for connection req.
# Similar to above, but for connections
ServerOption ReadUserPasswdTimeout 500000
# time to wiat for a user/passwd to be sent from a client. Increase this
# if there is a problem connecting to a server due to network overload\
ServerOption LogFileBaseName /data/koenneck/src/sics/tmp/server
# the path and base name of the internal server logfile to which all
# activity will be logged.
ServerOption ServerPort 2910
# the port number the server is going to listen at. The client MUST know
# this number in order to connect. It is in client.ini
ServerOption InterruptPort 2913
# The UDP port where the server will wait for Interrupts from clients.
# Obviously, clients wishing to interrupt need to know this number.
#---------------------------------------------------------------------------
# U S E R S
# than the SICS users are specified
# Syntax: SicsUser name password userRightsCode
SicsUser Mugger Diethelm 1
SicsUser User Rosy 2
SicsUser Spy 007 3

20
beam.tcl Normal file
View File

@ -0,0 +1,20 @@
#------------------------------------------------------------------------
# install a SPS-Controller
MakeSPS sps1 lnsp25.psi.ch 4000 7
#----------------- the beam command
proc beam {} {
#---------- read the SPS
set ret [catch {SPS1 adc 3} msg]
if {$ret != 0} {
ClientPut $msg
ClientPut "ERROR: SPS reading failed"
return
}
#--------- convert the data
set l [split $msg "="]
set raw [lindex $l 1]
set val [expr $raw/13.96]
return [format "beam = %f" $val]
}
Publish beam Spy

20
beamdt.tcl Normal file
View File

@ -0,0 +1,20 @@
#------------------------------------------------------------------------
# install a SPS-Controller
MakeSPS sps1 lnsp23.psi.ch 4000 6
#----------------- the beam command
proc beam {} {
#---------- read the SPS
set ret [catch {SPS1 adc 7} msg]
if {$ret != 0} {
ClientPut $msg
ClientPut "ERROR: SPS reading failed"
return
}
#--------- convert the data
set l [split $msg "="]
set raw [lindex $l 1]
set val [expr $raw/13.96]
return [format "beam = %f" $val]
}
Publish beam Spy

17
bit.h Normal file
View File

@ -0,0 +1,17 @@
/*--------------------------------------------------------------------------
Macros for handling bits in a character array. Stolen somewhere on the
internet. Working!
Dr. Mark Koennecke 15.6.1994
----------------------------------------------------------------------------*/
#include <limits.h> /* for CHAR_BIT */
#define BITMASK(bit) (1 << ((bit) % CHAR_BIT))
#define BITSLOT(bit) ((bit) / CHAR_BIT)
#define BITSET(ary, bit) ((ary)[BITSLOT(bit)] |= BITMASK(bit))
#define BITTEST(ary, bit) ((ary)[BITSLOT(bit)] & BITMASK(bit))
#define BITUNSET(ary, bit) ((ary)[BITSLOT(bit)] ^= BITMASK(bit))

999
bruker.c Normal file
View File

@ -0,0 +1,999 @@
/*-------------------------------------------------------------------------
B r u k e r
An environment control driver and an additonal wrapper function for
controlling a Bruker B-EC-1 magnet controller. This controller can
either control a current or control the current through an external hall
sensor mesuring the magnetic field. In both cases both values: the field
and the current must be readable.
copyright: see copyright.h
Mark Koennecke, October 1998
---------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <tcl.h>
#include <math.h>
#include <assert.h>
#include "fortify.h"
#include "sics.h"
#include "obpar.h"
#include "evcontroller.h"
#include "evcontroller.i"
#include "evdriver.i"
#include "hardsup/serialsinq.h"
#include "hardsup/el734_errcodes.h"
#include "hardsup/el734fix.h"
#include "bruker.h"
/*
#define debug 1
*/
/*-----------------------------------------------------------------------
The Bruker Data Structure
*/
typedef struct {
void *pData;
char *pHost;
int iPort;
int iChannel;
int iMode;
int iLastError;
} BrukerDriv, *pBrukerDriv;
/*-----------------------------------------------------------------------
A couple of defines for Bruker modes and special error conditions
*/
#define FIELD 100
#define CURRENT 200
/* errors */
#define NOFUNC -1601
#define BADARG -1602
#define NOACCESS -1603
#define BADRANGE -1604
#define ERRPENDING -1605
#define NOPOWER -1606
#define NOTFIELD -1607
#define BADINTERN -1608
#define NOCONN -1609
#define BTIMEOUT -1610
#define NOPOLUNIT -1620
/* polarity */
#define PPLUS 0
#define PMINUS 1
#define PBUSY 3
/* rmtrail.c */
extern char *rmtrail(char *p);
/*---------------------------------------------------------------------------
This Bruker thing has a lot of internal error conditions and a few nasty
habits. Such as to lock up after an error ocurred until the error is reset.
Or to switch the power off, when a current above the limit is requested
after setting a bad value for the magnetic field. These problems can be
detected by analysing the return values from the Bruker. Usually the Bruker
returns the command given to the user plus additional values if requested.
On an error a string of the type E0n is appended to the command echo with
n being a small integer. In order to handle this all commands to the Bruker
are processed through this special function which takes care of the error
handling.
*/
static int BrukerCommand(pBrukerDriv self, char *pCommand,
char *pReplyBuffer, int iReplyLen)
{
int iTest, iCode;
char *pPtr;
assert(self);
assert(iReplyLen > 20); /* so small a buffer will hide errors */
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
/* send the command to the Bruker */
rmtrail(pCommand);
iTest = SerialWriteRead(&(self->pData), pCommand,pReplyBuffer, iReplyLen);
#ifdef debug
printf("Comm: %s , Reply %s\n",pCommand,pReplyBuffer);
#endif
if(iTest != 1) /* communication error */
{
self->iLastError = iTest;
return 0;
}
/* identify timeout */
if(strstr(pReplyBuffer,"?TMO") != NULL)
{
self->iLastError = BTIMEOUT;
return 0;
}
/* try to find a E0 response indicating a Bruker error */
if( (pPtr = strstr(pReplyBuffer,"E0")) == NULL)
{
return 1;
}
/* decode the error */
sscanf(pPtr+1,"%x",&iCode);
switch(iCode)
{
case 1:
self->iLastError = NOFUNC;
break;
case 2:
self->iLastError = BADARG;
break;
case 4:
self->iLastError = NOACCESS;
break;
case 5:
self->iLastError = BADRANGE;
break;
case 7:
self->iLastError = ERRPENDING;
break;
case 9:
self->iLastError = NOPOWER;
break;
case 10:
self->iLastError = NOTFIELD;
break;
default:
self->iLastError = BADINTERN;
break;
}
return 0;
}
/*-------------------------------------------------------------------------*/
int BrukerReadField(pEVControl pEva, float *fField)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[6];
char *pPtr,*pSign;
int iSign = 1;
float fVal;
self = (pBrukerDriv)pEva->pDriv->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
strcpy(pCommand,"FIE/");
iRet = BrukerCommand(self,pCommand,pBueffel,79);
if(!iRet)
{
*fField = -99;
return 0;
}
pPtr = pBueffel+4; /* skip over echo */
/* deal with obstructing sign */
if( (pSign = strchr(pPtr,'+')) != NULL)
{
*pSign = ' ';
iSign = 1;
}
if( (pSign = strchr(pPtr,'-')) != NULL)
{
*pSign = ' ';
iSign = -1;
}
sscanf(pPtr,"%f",&fVal);
*fField = iSign * fVal;
return 1;
}
/*-------------------------------------------------------------------------*/
int BrukerReadCurrent(pEVControl pEva, float *fField)
{
pBrukerDriv self = NULL;
int iRet, iSign = 1;
char pBueffel[80];
char pCommand[6];
char *pPtr, *pSign = NULL;
float fVal;
self = (pBrukerDriv)pEva->pDriv->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
strcpy(pCommand,"CHN/");
iRet = BrukerCommand(self,pCommand,pBueffel,79);
if(!iRet)
{
*fField = -99;
return 0;
}
pPtr = pBueffel+4; /* skip over echo */
/* deal with obstructing sign */
if( (pSign = strchr(pPtr,'+')) != NULL)
{
*pSign = ' ';
iSign = 1;
}
if( (pSign = strchr(pPtr,'-')) != NULL)
{
*pSign = ' ';
iSign = -1;
}
sscanf(pPtr,"%f",&fVal);
*fField = iSign * fVal;
return 1;
}
/*-------------------------------------------------------------------------*/
static int BrukerGet(pEVDriver pEva, float *fValue)
{
pBrukerDriv self = NULL;
int iRet, iSign = 1;
char pBueffel[80];
char pCommand[6];
char *pPtr, *pSign = NULL;
float fVal;
self = (pBrukerDriv)pEva->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
if(self->iMode == FIELD)
{
strcpy(pCommand,"CUF/");
iRet = BrukerCommand(self,pCommand,pBueffel,79);
}
else if(self->iMode == CURRENT)
{
strcpy(pCommand,"CUR/");
iRet = BrukerCommand(self,pCommand,pBueffel,79);
}
else
{
/* programming error */
assert(1);
}
if(!iRet)
{
*fValue = -99;
return 0;
}
pPtr = pBueffel+4; /* skip over echo */
/* deal with obstructing sign */
if( (pSign = strchr(pPtr,'+')) != NULL)
{
*pSign = ' ';
iSign = 1;
}
if( (pSign = strchr(pPtr,'-')) != NULL)
{
*pSign = ' ';
iSign = -1;
}
sscanf(pPtr,"%f",&fVal);
*fValue = iSign * fVal;
return 1;
}
/*-------------------------------------------------------------------------*/
static int BrukerRun(pEVDriver pEva, float fVal)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[40];
char *pPtr;
self = (pBrukerDriv)pEva->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
if(self->iMode == FIELD)
{
sprintf(pCommand,"PTF=%-6.2f",fVal);
iRet = BrukerCommand(self,pCommand,pBueffel,79);
}
else if(self->iMode == CURRENT)
{
sprintf(pCommand,"PNT=%-6.2f",fVal);
iRet = BrukerCommand(self,pCommand,pBueffel,79);
}
else
{
/* programming error */
assert(1);
}
if(!iRet)
{
return 0;
}
return 1;
}
/*------------------------------------------------------------------------*/
static int BrukerError(pEVDriver pEva, int *iCode, char *pError,
int iErrLen)
{
pBrukerDriv self = NULL;
self = (pBrukerDriv)pEva->pPrivate;
assert(self);
*iCode = self->iLastError;
switch(*iCode)
{
case NOFUNC:
strncpy(pError,
"Function not supported",
iErrLen);
break;
case BADINTERN:
case BADARG:
strncpy(pError,
"Programming problem, reset Controller & contact Programmer",
iErrLen);
break;
case NOTFIELD:
strncpy(pError,"Bruker not switched to field mode",iErrLen);
break;
case BADRANGE:
strncpy(pError,"Requested value out of range",iErrLen);
break;
case NOACCESS:
strncpy(pError,"No Access, check key position at Controller",
iErrLen);
break;
case ERRPENDING:
strncpy(pError,"Error condition pending in Bruker Controller",
iErrLen);
break;
case NOPOWER:
strncpy(pError,
"Power OFF as consequence of some error in Bruker Controller",
iErrLen);
break;
case NOCONN:
strncpy(pError,"No Connection to Bruker Controller",iErrLen);
break;
case BTIMEOUT:
strncpy(pError,"Timeout at serial port",iErrLen);
break;
case NOPOLUNIT:
strncpy(pError,"No polarity switching unit, try setting negative current",
iErrLen);
break;
default:
SerialError(*iCode,pError,iErrLen);
break;
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int BrukerSend(pEVDriver pEva, char *pCommand, char *pReply,
int iReplyLen)
{
pBrukerDriv self = NULL;
int iRet;
self = (pBrukerDriv)pEva->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
iRet = SerialWriteRead(&(self->pData),pCommand, pReply, iReplyLen);
if(iRet != 1)
{
self->iLastError = iRet;
return 0;
}
return 1;
}
/*--------------------------------------------------------------------------*/
static int BrukerInit(pEVDriver pEva)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80], pCommand[20];
self = (pBrukerDriv)pEva->pPrivate;
assert(self);
/* open port connection */
self->pData = NULL;
iRet = SerialOpen(&(self->pData),self->pHost, self->iPort, self->iChannel);
if(iRet != 1)
{
self->iLastError = iRet;
return 0;
}
/* configure serial port terminators */
SerialSendTerm(&(self->pData),"\r");
SerialATerm(&(self->pData),"1\r\n");
/* set power on */
strcpy(pCommand,"DCP=1");
iRet = SerialWriteRead(&(self->pData),pCommand,pBueffel,80);
if(iRet != 1)
{
self->iLastError = iRet;
return 0;
}
/* switch to current mode as default init mode */
self->iMode = CURRENT;
strcpy(pCommand,"EXT=0");
iRet = SerialWriteRead(&(self->pData),pCommand,pBueffel,80);
if(iRet != 1)
{
self->iLastError = iRet;
return 0;
}
return 1;
}
/*-------------------------------------------------------------------------*/
static int BrukerClose(pEVDriver pEva)
{
pBrukerDriv self = NULL;
self = (pBrukerDriv)pEva->pPrivate;
assert(self);
SerialClose(&(self->pData));
self->pData = 0;
return 1;
}
/*---------------------------------------------------------------------------*/
static int BrukerFix(pEVDriver self, int iError)
{
pBrukerDriv pMe = NULL;
int iRet;
char pCommand[20], pBueffel[80];
assert(self);
pMe = (pBrukerDriv )self->pPrivate;
assert(pMe);
switch(iError)
{
/* network errors */
case EL734__BAD_FLUSH:
case EL734__BAD_RECV:
case EL734__BAD_RECV_NET:
case EL734__BAD_RECV_UNKN:
case EL734__BAD_RECVLEN:
case EL734__BAD_RECV1:
case EL734__BAD_RECV1_PIPE:
case EL734__BAD_RNG:
case EL734__BAD_SEND:
case EL734__BAD_SEND_PIPE:
case EL734__BAD_SEND_NET:
case EL734__BAD_SEND_UNKN:
case EL734__BAD_SENDLEN:
BrukerClose(self);
iRet = BrukerInit(self);
if(iRet)
{
return DEVREDO;
}
else
{
return DEVFAULT;
}
break;
case EL734__FORCED_CLOSED:
case NOCONN:
iRet = BrukerInit(self);
if(iRet)
{
return DEVREDO;
}
else
{
return DEVFAULT;
}
break;
/* fixable Bruker Errors */
case ERRPENDING:
strcpy(pCommand,"RST=0");
iRet = BrukerCommand(pMe,pCommand, pBueffel,79);
if(iRet)
{
return DEVREDO;
}
else
{
return DEVFAULT;
}
break;
case NOPOWER:
strcpy(pCommand,"RST=0");
iRet = BrukerCommand(pMe,pCommand, pBueffel,79);
strcpy(pCommand,"DCP=1");
iRet = BrukerCommand(pMe,pCommand, pBueffel,79);
if(iRet)
{
return DEVREDO;
}
else
{
return DEVFAULT;
}
break;
case NOTFIELD:
strcpy(pCommand,"EXT=2");
iRet = BrukerCommand(pMe,pCommand, pBueffel,79);
if(iRet)
{
return DEVREDO;
}
else
{
return DEVFAULT;
}
break;
/* handable protocoll errors */
case EL734__BAD_TMO:
case BTIMEOUT:
case NOFUNC:
return DEVREDO;
break;
default:
return DEVFAULT;
break;
}
return DEVFAULT;
}
/*------------------------------------------------------------------------*/
void KillBruker(void *pData)
{
pBrukerDriv pMe = NULL;
pMe = (pBrukerDriv)pData;
assert(pMe);
if(pMe->pHost)
{
free(pMe->pHost);
}
free(pMe);
}
/*------------------------------------------------------------------------*/
pEVDriver CreateBrukerDriver(int argc, char *argv[])
{
pEVDriver pNew = NULL;
pBrukerDriv pSim = NULL;
/* check for arguments */
if(argc < 3)
{
return NULL;
}
pNew = CreateEVDriver(argc,argv);
pSim = (pBrukerDriv)malloc(sizeof(BrukerDriv));
memset(pSim,0,sizeof(BrukerDriv));
if(!pNew || !pSim)
{
return NULL;
}
pNew->pPrivate = pSim;
pNew->KillPrivate = KillBruker;
/* initalise pBrukerDriver */
pSim->iLastError = 0;
pSim->pHost = strdup(argv[0]);
pSim->iPort = atoi(argv[1]);
pSim->iChannel = atoi(argv[2]);
/* initialise function pointers */
pNew->SetValue = BrukerRun;
pNew->GetValue = BrukerGet;
pNew->Send = BrukerSend;
pNew->GetError = BrukerError;
pNew->TryFixIt = BrukerFix;
pNew->Init = BrukerInit;
pNew->Close = BrukerClose;
return pNew;
}
/*-------------------------------------------------------------------------*/
int BrukerSetMode(pEVControl pEva, SConnection *pCon, int iMode)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[6];
char *pPtr;
self = (pBrukerDriv)pEva->pDriv->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
if(iMode == CURRENT)
{
strcpy(pCommand,"EXT=0");
}
else if(iMode == FIELD)
{
strcpy(pCommand,"EXT=2");
}
else
{
SCWrite(pCon,"ERROR: Internal: invalid mode for Bruker given",eError);
return 0;
}
iRet = BrukerCommand(self,pCommand,pBueffel,79);
if(!iRet)
{
strcpy(pBueffel,"ERROR:");
BrukerError(pEva->pDriv,&iRet,(pBueffel+7),70);
SCWrite(pCon,pBueffel,eError);
return 0;
}
self->iMode = iMode;
return 1;
}
/*-------------------------------------------------------------------------*/
int BrukerGetPolarity(pEVControl pEva, SConnection *pCon, int *iMode)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[6];
char *pPtr;
self = (pBrukerDriv)pEva->pDriv->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
strcpy(pCommand,"POL/");
iRet = BrukerCommand(self,pCommand,pBueffel,79);
if(!iRet)
{
strcpy(pBueffel,"ERROR:");
BrukerError(pEva->pDriv,&iRet,(pBueffel+7),70);
SCWrite(pCon,pBueffel,eError);
return 0;
}
pPtr = pBueffel+4;
sscanf(pPtr,"%d",iMode);
return 1;
}
/*------------------------------------------------------------------------*/
int BrukerSetPolarity(pEVControl pEva, SConnection *pCon, int iMode)
{
pBrukerDriv self = NULL;
int iRet;
char pBueffel[80];
char pCommand[6];
char *pPtr;
self = (pBrukerDriv)pEva->pDriv->pPrivate;
assert(self);
if(self->pData == NULL)
{
self->iLastError = NOCONN;
return 0;
}
if(iMode == PPLUS)
{
strcpy(pCommand,"POL=0");
}
else if(iMode == PMINUS)
{
strcpy(pCommand,"POL=1");
}
else
{
assert(1); /* programming error */
}
iRet = BrukerCommand(self,pCommand,pBueffel,79);
if( (strstr(pBueffel,"POL=0E01") != NULL) ||
(strstr(pBueffel,"POL=1E01") != NULL) )
{
self->iLastError = NOPOLUNIT;
iRet = 0;
}
if(!iRet)
{
strcpy(pBueffel,"ERROR:");
BrukerError(pEva->pDriv,&iRet,(pBueffel+6),70);
SCWrite(pCon,pBueffel,eError);
return 0;
}
return 1;
}
/*--------------------------------------------------------------------------
handle Bruker specific commands:
- polarity for switching polarity
- field for reading field
- current for reading current
- mode for setting and retrieving the current control mode
- list append our own stuff to the rest
in all other cases fall back and call EVControllerWrapper to handle it or
eventually throw an error.
*/
int BrukerAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pEVControl self = NULL;
int iRet, iMode;
char pBueffel[256];
pBrukerDriv pMe = NULL;
float fVal;
self = (pEVControl)pData;
assert(self);
pMe = (pBrukerDriv)self->pDriv->pPrivate;
assert(pMe);
if(argc > 1)
{
strtolower(argv[1]);
/*------ polarity */
if(strcmp(argv[1],"polarity") == 0)
{
if(argc > 2) /* set case */
{
strtolower(argv[2]);
if(strcmp(argv[2],"plus") == 0)
{
iMode = PPLUS;
}
else if(strcmp(argv[2],"minus") == 0)
{
iMode = PMINUS;
}
else
{
sprintf(pBueffel,"ERROR: %s is no knwon polarity mode", argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* check permission */
if(!SCMatchRights(pCon,usUser))
{
return 0;
}
/* do it */
iRet = BrukerSetPolarity(self,pCon,iMode);
if(iRet)
{
SCSendOK(pCon);
return 1;
}
else
{
return 0;
}
}
else /* get case */
{
iRet = BrukerGetPolarity(self,pCon,&iMode);
if(iRet)
{
if(iMode == PPLUS)
{
sprintf(pBueffel,"%s.polarity = plus",argv[0]);
}
else if (iMode == PMINUS)
{
sprintf(pBueffel,"%s.polarity = minus",argv[0]);
}
else
{
assert(1); /* programming problem */
}
SCWrite(pCon,pBueffel,eValue);
return 1;
}
}
}
/*-------- control mode */
else if(strcmp(argv[1],"mode") == 0)
{
if(argc > 2) /* set case */
{
strtolower(argv[2]);
if(strcmp(argv[2],"field") == 0)
{
iMode = FIELD;
}
else if(strcmp(argv[2],"current") == 0)
{
iMode = CURRENT;
}
else
{
sprintf(pBueffel,"ERROR: %s is no known control mode", argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* check permission */
if(!SCMatchRights(pCon,usUser))
{
return 0;
}
/* do it */
iRet = BrukerSetMode(self,pCon,iMode);
if(iRet)
{
SCSendOK(pCon);
return 1;
}
else
{
return 0;
}
}
else /* get case */
{
if(pMe->iMode == FIELD)
{
sprintf(pBueffel,"%s.mode = field",argv[0]);
}
else if (pMe->iMode == CURRENT)
{
sprintf(pBueffel,"%s.mode = current",argv[0]);
}
else
{
assert(1); /* programming problem */
}
SCWrite(pCon,pBueffel,eValue);
return 1;
}
}
/*-----------field */
else if(strcmp(argv[1],"field") == 0)
{
iRet = BrukerReadField(self,&fVal);
if(!iRet)
{
strcpy(pBueffel,"ERROR: ");
self->pDriv->GetError(self->pDriv,&iMode,pBueffel+7,240);
SCWrite(pCon,pBueffel,eError);
return 0;
}
sprintf(pBueffel,"%s.field = %f Tesla",argv[0],fVal);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
/*----------- current */
else if(strcmp(argv[1],"current") == 0)
{
iRet = BrukerReadCurrent(self,&fVal);
if(!iRet)
{
strcpy(pBueffel,"ERROR: ");
self->pDriv->GetError(self->pDriv,&iMode,pBueffel+7,240);
SCWrite(pCon,pBueffel,eError);
return 0;
}
sprintf(pBueffel,"%s.current = %f A",argv[0],fVal);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
/*--------- list */
else if(strcmp(argv[1],"list") == 0)
{
/* print generals first */
EVControlWrapper(pCon,pSics,pData,argc,argv);
/* print our add on stuff */
iRet = BrukerReadCurrent(self,&fVal);
if(!iRet)
{
strcpy(pBueffel,"ERROR: ");
self->pDriv->GetError(self->pDriv,&iMode,pBueffel+7,240);
SCWrite(pCon,pBueffel,eError);
}
else
{
sprintf(pBueffel,"%s.current = %f A",argv[0],fVal);
SCWrite(pCon,pBueffel,eValue);
}
iRet = BrukerReadField(self,&fVal);
if(!iRet)
{
strcpy(pBueffel,"ERROR: ");
self->pDriv->GetError(self->pDriv,&iMode,pBueffel+7,240);
SCWrite(pCon,pBueffel,eError);
}
else
{
sprintf(pBueffel,"%s.field = %f Tesla",argv[0],fVal);
SCWrite(pCon,pBueffel,eValue);
}
if(pMe->iMode == FIELD)
{
sprintf(pBueffel,"%s.mode = field",argv[0]);
}
else if (pMe->iMode == CURRENT)
{
sprintf(pBueffel,"%s.mode = current",argv[0]);
}
else
{
sprintf(pBueffel,"ERROR: Programming error");
}
SCWrite(pCon,pBueffel,eValue);
iRet = BrukerGetPolarity(self,pCon,&iMode);
if(iRet)
{
if(iMode == PPLUS)
{
sprintf(pBueffel,"%s.polarity = plus",argv[0]);
}
else if (iMode == PMINUS)
{
sprintf(pBueffel,"%s.polarity = minus",argv[0]);
}
else if(iMode == PBUSY)
{
sprintf(pBueffel,"%s.polarity = busy",argv[0]);
}
else
{
sprintf(pBueffel,"ERROR: Programming problem");
}
SCWrite(pCon,pBueffel,eValue);
}
else
{
SCWrite(pCon,"ERROR: cannot read polarity",eError);
}
return 1;
}
else
{
return EVControlWrapper(pCon,pSics,pData,argc,argv);
}
}
return EVControlWrapper(pCon,pSics,pData,argc,argv);
}

25
bruker.h Normal file
View File

@ -0,0 +1,25 @@
/*-------------------------------------------------------------------------
B r u k e r
An environment control driver and an additonal wrapper function for
controlling a Bruker B-EC-1 magnet controller. This controller can
either control a current or control the current through an external hall
sensor mesuring the magnetic field. In both cases both values: the field
and the current must be readable.
copyright: see copyright.h
Mark Koennecke, October 1998
---------------------------------------------------------------------------*/
#ifndef BRUKERMAGNET
#define BRUKERMAGNET
pEVDriver CreateBrukerDriver(int argc, char *argv[]);
int BrukerReadField(pEVControl self, float *fField);
int BrukerReadCurrent(pEVControl self, float *fCurrent);
int BrukerAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif

64
bruker.tex Normal file
View File

@ -0,0 +1,64 @@
\subsubsection{Bruker Magnet Controller B-EC-1}
SANS is using a Bruker magnet controller. This controller is integrated
into SICS as a derivate of an environment controller. The Bruker controller
can be operated in two modes: in the first the current is controlled,
in the second the current
is controlled by an external hall sensor giving the magnetic field. Whatever
is the controlling sensor, the magnetic field and the current need to be
read. Furthermore this device supports switching the polarity. All this is
achieved with a special driver and an additional wrapper function for
handling extra commands. All this is implemented in the file bruker.h
and bruker.c. The functions defined are:
\begin{verbatim}
pEVDriver CreateBrukerDriver(int argc, char *argv[]);
int BrukerReadField(pEVControl self, float *fField);
int BrukerReadCurrent(pEVControl self, float *fCurrent);
int BrukerAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
\end{verbatim}
\begin{description}
\item[CreateBrukerDriver] creates a driver for the bruker magnet
controller.
\item[BrukerReadField] reads the current magnetic field.
\item[BrukerReadCurrent] reads the current current in Ampere.
\item[BrukerAction] a special SICS interpreter wrapper function for
the Bruker Magnet. This function handles the few special Bruker
commands and passes everything else to the standard environment
controller handler function.
\end{description}

64
bruker.w Normal file
View File

@ -0,0 +1,64 @@
\subsubsection{Bruker Magnet Controller B-EC-1}
SANS is using a Bruker magnet controller. This controller is integrated
into SICS as a derivate of an environment controller. The Bruker controller
can be operated in two modes: in the first the current is controlled,
in the second the current
is controlled by an external hall sensor giving the magnetic field. Whatever
is the controlling sensor, the magnetic field and the current need to be
read. Furthermore this device supports switching the polarity. All this is
achieved with a special driver and an additional wrapper function for
handling extra commands. All this is implemented in the file bruker.h
and bruker.c. The functions defined are:
\begin{verbatim}
pEVDriver CreateBrukerDriver(int argc, char *argv[]);
int BrukerReadField(pEVControl self, float *fField);
int BrukerReadCurrent(pEVControl self, float *fCurrent);
int BrukerAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
\end{verbatim}
\begin{description}
\item[CreateBrukerDriver] creates a driver for the bruker magnet
controller.
\item[BrukerReadField] reads the current magnetic field.
\item[BrukerReadCurrent] reads the current current in Ampere.
\item[BrukerAction] a special SICS interpreter wrapper function for
the Bruker Magnet. This function handles the few special Bruker
commands and passes everything else to the standard environment
controller handler function.
\end{description}

584
buffer.c Normal file
View File

@ -0,0 +1,584 @@
/*--------------------------------------------------------------------------
L N S R \"U N B U F F E R
Mark Koennecke, January 1997
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <tcl.h>
#include "fortify.h"
#include "lld.h"
#include "lld_blob.h"
#include "lld_str.h"
#include "conman.h"
#include "obdes.h"
#include "buffer.h"
#include "fupa.h"
#include "splitter.h"
#include "ruli.h"
/*-------------------------------------------------------------------------*/
static int SaveBuffer(void *pData, char *name, FILE *fd)
{
pRuenBuffer self = NULL;
int iRet;
char *pPtr = NULL;
assert(fd);
assert(pData);
self = (pRuenBuffer)pData;
fprintf(fd,"# RuenBuffer %s\n",name);
fprintf(fd,"Buf new %s\n",name);
iRet = LLDnodePtr2First(self->iLineList);
while(iRet != 0)
{
pPtr = (char *)LLDnodePtr(self->iLineList);
fprintf(fd,"%s append %s\n",name,pPtr);
iRet = LLDnodePtr2Next(self->iLineList);
}
return 1;
}
/*--------------------------------------------------------------------------*/
pRuenBuffer CreateRuenBuffer(char *name)
{
pRuenBuffer pNew = NULL;
pNew = (pRuenBuffer)malloc(sizeof(RuenBuffer));
if(!pNew)
{
return NULL;
}
pNew->pDes = CreateDescriptor("SicsRuenBuffer");
if(!pNew->pDes)
{
free(pNew);
return NULL;
}
pNew->name = strdup(name);
Fortify_CheckAllMemory();
pNew->iLineList = LLDblobCreate();
if(pNew->iLineList == -1)
{
DeleteDescriptor(pNew->pDes);
free(pNew->name);
free(pNew);
return NULL;
}
pNew->pDes->SaveStatus = SaveBuffer;
return pNew;
}
/*--------------------------------------------------------------------------*/
static void DeleteLineBuffer(int iList)
{
int iRet;
char *pPtr;
iRet = LLDnodePtr2First(iList);
while(iRet != 0)
{
pPtr = (char *)LLDnodePtr(iList);
free(pPtr);
iRet = LLDnodePtr2Next(iList);
}
LLDdelete(iList);
}
/*-------------------------------------------------------------------------*/
void DeleteRuenBuffer(void *self)
{
int iRet;
pRuenBuffer pOld = (pRuenBuffer)self;
assert(pOld);
/* delete line buffer */
DeleteLineBuffer(pOld->iLineList);
if(pOld->name)
{
free(pOld->name);
}
if(pOld->pDes)
{
DeleteDescriptor(pOld->pDes);
}
free(pOld);
}
/*--------------------------------------------------------------------------*/
pRuenBuffer CopyRuenBuffer(pRuenBuffer pOld, char *name)
{
pRuenBuffer pNew = NULL;
int iRet;
char *pPtr;
pNew = CreateRuenBuffer(name);
if(!pNew)
{
return NULL;
}
/* copy list*/
iRet = LLDnodePtr2First(pOld->iLineList);
while(iRet != 0)
{
pPtr = (char *)LLDnodePtr(pOld->iLineList);
LLDstringAdd(pNew->iLineList,pPtr);
iRet = LLDnodePtr2Next(pOld->iLineList);
}
return pNew;
}
/*-------------------------------------------------------------------------*/
int BufferAppendLine(pRuenBuffer self, char *line)
{
assert(self);
return LLDstringAppend(self->iLineList,line);
}
/*------------------------------------------------------------------------*/
int BufferDel(pRuenBuffer self, int i)
{
int iNum;
int iRet;
assert(self);
iRet = LLDnodePtr2First(self->iLineList);
iNum = 0;
while(iRet != 0)
{
if(iNum == i)
{
LLDstringDelete(self->iLineList);
return 1;
}
iNum++;
iRet = LLDnodePtr2Next(self->iLineList);
}
return 0;
}
/*------------------------------------------------------------------------*/
int BufferInsertAfter(pRuenBuffer self, int i, char *line)
{
int iNum;
int iRet;
assert(self);
iRet = LLDnodePtr2First(self->iLineList);
iNum = 0;
while(iRet != 0)
{
if(iNum == i)
{
LLDstringInsert(self->iLineList, line);
return 1;
}
iNum++;
iRet = LLDnodePtr2Next(self->iLineList);
}
return 0;
}
/*------------------------------------------------------------------------*/
int BufferPrint(pRuenBuffer self, SConnection *pCon)
{
int iRet;
char *pPtr = NULL;
char pBueffel[512];
int iCount = 1;
iRet = LLDnodePtr2First(self->iLineList);
sprintf(pBueffel,"Listing for Bueffer %s",self->name);
SCWrite(pCon,pBueffel,eValue);
while(iRet != 0)
{
pPtr = (char *)LLDnodePtr(self->iLineList);
sprintf(pBueffel,"[%d] %s",iCount,pPtr);
SCWrite(pCon,pBueffel,eValue);
iRet = LLDnodePtr2Next(self->iLineList);
iCount++;
}
return 1;
}
/*------------------------------------------------------------------------*/
extern char *StrReplace(char *str, char *old, char *pNew);
/* realised in Strrepl.c
*/
int BufferReplace(pRuenBuffer self, char *pattern, char *pReplace)
{
int iRet;
char *pPtr = NULL;
char pBueffel[1024];
char *pRet;
iRet = LLDnodePtr2First(self->iLineList);
while(iRet != 0)
{
pPtr = (char *)LLDnodePtr(self->iLineList);
strcpy(pBueffel,pPtr);
pRet = NULL;
pRet = StrReplace(pBueffel,pattern,pReplace);
if(pRet)
{
LLDstringDelete(self->iLineList);
iRet = LLDnodePtr2Next(self->iLineList);
LLDnodePtr2Prev(self->iLineList);
if(iRet)
{
LLDstringInsert(self->iLineList,pBueffel);
}
else
{
LLDstringAppend(self->iLineList,pBueffel);
}
}
iRet = LLDnodePtr2Next(self->iLineList);
}
return 1;
}
/*-----------------------------------------------------------------------*/
int BufferRun(pRuenBuffer self, SConnection *pCon, SicsInterp *pSics)
{
int iRet;
char *pPtr = NULL;
int iInt, iRes;
iRes = 1;
iRet = LLDnodePtr2First(self->iLineList);
while(iRet != 0)
{
pPtr = (char *)LLDnodePtr(self->iLineList);
iInt = InterpExecute(pSics,pCon,pPtr);
if(!iInt)
{
iRes = 0;
}
iRet = LLDnodePtr2Next(self->iLineList);
}
return iRes;
}
/*------------------------------------------------------------------------*/
int BufferSave(pRuenBuffer self, char *file)
{
int iRet;
char *pPtr = NULL;
FILE *fd = NULL;
fd = fopen(file,"w");
if(fd == NULL)
{
return 0;
}
iRet = LLDnodePtr2First(self->iLineList);
while(iRet != 0)
{
pPtr = (char *)LLDnodePtr(self->iLineList);
fprintf(fd,"%s\n",pPtr);
iRet = LLDnodePtr2Next(self->iLineList);
}
fclose(fd);
return 1;
}
/*------------------------------------------------------------------------*/
int BufferLoad(pRuenBuffer self, char *file)
{
int iRet;
char *pPtr = NULL;
FILE *fd = NULL;
char pBueffel[256];
fd = fopen(file,"r");
if(fd == NULL)
{
return 0;
}
pPtr = fgets(pBueffel,255,fd);
while(pPtr != NULL)
{
LLDstringAppend(self->iLineList,pBueffel);
pPtr = fgets(pBueffel,255,fd);
}
fclose(fd);
return 1;
}
/*------------------------------------------------------------------------*/
pRuenBuffer FindRuenBuffer(SicsInterp *pSics, char *name)
{
pRuenBuffer pBuf = NULL;
CommandList *pCom = NULL;
pCom = FindCommand(pSics,name);
if(!pCom)
{
return NULL;
}
pBuf = (pRuenBuffer)pCom->pData;
if(!pBuf)
{
return NULL;
}
if(!pBuf->pDes)
{
return NULL;
}
if(strcmp(pBuf->pDes->name,"SicsRuenBuffer") != 0)
{
return NULL;
}
return pBuf;
}
/*-------------------------------------------------------------------------*/
int InitBufferSys(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pRuenStack pStack = NULL;
pStack = CreateRuenStack();
if(!pStack)
{
SCWrite(pCon,"ERROR: No memory to create Ruen-Stack",eError);
return 0;
}
AddCommand(pSics,"Buf",BufferCommand,NULL,NULL);
AddCommand(pSics,"Stack",RuenStackAction,DeleteRuenStack,pStack);
return 1;
}
/*------------------------------------------------------------------------*/
int BufferCommand(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
int iRet, iRet2;
char pBueffel[512];
char **argx;
FuPaResult PaRes;
pRuenBuffer pBuf = NULL;
FuncTemplate BufferTemplate[] = {
{"new",1,{FUPATEXT} },
{"del",1,{FUPATEXT} },
{"copy",2,{FUPATEXT, FUPATEXT}},
};
assert(pCon);
assert(pSics);
/* minimum user to use this */
if(!SCMatchRights(pCon,usUser))
{
return 0;
}
/* parse function args */
argtolower(argc,argv);
argx = &argv[1];
iRet = EvaluateFuPa((pFuncTemplate)&BufferTemplate,3,argc-1,argx,&PaRes);
if(iRet < 0)
{
sprintf(pBueffel,"%s",PaRes.pError);
SCWrite(pCon,pBueffel,eError);
return 0;
}
switch(iRet)
{
case 0: /* new */
pBuf = CreateRuenBuffer(PaRes.Arg[0].text);
if(!pBuf)
{
SCWrite(pCon, "ERROR: Out of memory allocating buffer",eError);
return 0;
}
iRet2 = AddCommand(pSics,pBuf->name,BufferAction,DeleteRuenBuffer,
(void *)pBuf);
if(!iRet2)
{
sprintf(pBueffel,"ERROR: duplicate command %s not created",pBuf->name);
SCWrite(pCon,pBueffel,eError);
DeleteRuenBuffer((void *)pBuf);
return 0;
}
return 1;
break;
case 1: /* del */
return RemoveCommand(pSics,PaRes.Arg[0].text);
break;
case 2: /* copy */
pBuf = FindRuenBuffer(pSics,PaRes.Arg[0].text);
if(!pBuf)
{
sprintf(pBueffel,"ERROR: Buffer %s not found",
PaRes.Arg[0].text);
SCWrite(pCon,pBueffel,eError);
return 0;
}
pBuf = CopyRuenBuffer(pBuf,PaRes.Arg[1].text);
if(!pBuf)
{
sprintf(pBueffel,"ERROR: creating buffer %s ",
PaRes.Arg[1].text);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet2 = AddCommand(pSics,pBuf->name,BufferAction,DeleteRuenBuffer,
(void *)pBuf);
if(!iRet2)
{
sprintf(pBueffel,"ERROR: duplicate command %s not created",pBuf->name);
SCWrite(pCon,pBueffel,eError);
DeleteRuenBuffer((void *)pBuf);
return 0;
}
return 1;
break;
default:
assert(0);
break;
}
assert(0);
}
/*-------------------------------------------------------------------------*/
int BufferAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
int iRet, iRet2;
char pBueffel[512];
char **argx;
FuPaResult PaRes;
pRuenBuffer pBuf = NULL;
FuncTemplate BufferTemplate[] = {
{"append",0,{FUPATEXT} },
{"del",1,{FUPAINT} },
{"ins",1,{FUPAINT}},
{"save",1,{FUPATEXT}},
{"load",1,{FUPATEXT}},
{"subst",2,{FUPATEXT,FUPATEXT}},
{"print",0,{0,0}},
{"run",0,{0,0}},
NULL
};
assert(pCon);
assert(pSics);
pBuf = (pRuenBuffer)pData;
assert(pBuf);
/* You need to be user in order to do this */
if(!SCMatchRights(pCon,usUser))
{
return 0;
}
/* parse function args */
argx = &argv[1];
strtolower(argx[0]);
iRet = EvaluateFuPa((pFuncTemplate)&BufferTemplate,8,argc-1,argx,&PaRes);
if(iRet < 0)
{
sprintf(pBueffel,"%s",PaRes.pError);
SCWrite(pCon,pBueffel,eError);
return 0;
}
switch(iRet)
{
case 0: /* append */
argx = &argv[2];
Arg2Text(argc-2,argx,pBueffel,511);
BufferAppendLine(pBuf,pBueffel);
SCSendOK(pCon);
return 1;
break;
case 1: /* del */
iRet2 = BufferDel(pBuf,PaRes.Arg[0].iVal);
if(iRet2)
SCSendOK(pCon);
break;
case 2: /* ins */
argx = &argv[3];
Arg2Text(argc-3,argx,pBueffel,511);
iRet2 = BufferInsertAfter(pBuf,PaRes.Arg[0].iVal,pBueffel);
if(iRet2)
SCSendOK(pCon);
return iRet2;
break;
case 3: /* save */
iRet2 = BufferSave(pBuf,PaRes.Arg[0].text);
if(!iRet2)
{
sprintf(pBueffel,"ERROR: cannot open %s for writing",
PaRes.Arg[0].text);
SCWrite(pCon,pBueffel,eError);
return 0;
}
else
{
SCSendOK(pCon);
return 1;
}
break;
case 4: /* load */
iRet2 = BufferLoad(pBuf,PaRes.Arg[0].text);
if(!iRet2)
{
sprintf(pBueffel,"ERROR: cannot open %s for reading ",
PaRes.Arg[0].text);
SCWrite(pCon,pBueffel,eError);
return 0;
}
else
{
SCSendOK(pCon);
return 1;
}
break;
case 5: /* subst */
iRet2 = BufferReplace(pBuf,PaRes.Arg[0].text,PaRes.Arg[1].text);
if(iRet2)
SCSendOK(pCon);
break;
case 6: /* print */
return BufferPrint(pBuf,pCon);
break;
case 7: /* run */
return BufferRun(pBuf,pCon,pSics);
default:
assert(0);
}
return 1;
}

94
buffer.h Normal file
View File

@ -0,0 +1,94 @@
/*---------------------------------------------------------------------------
T H E L N S R \" U N B U F F E R
The LNS has devised a special scheme to operate an instrument
via R\"un sequeneces and buffers. A R\"unbuffer is a series of
commands which are collected in a buffer. This buffer is
implemented here. A buffer can be added to, printed loaded from
a file etc. and can be executed.
The next schem is the R\"unlist which is a stack of R\"unbuffers.
That list can be exeuted as well. It gets a buffer from the
bottom of the stack and executes it and does so until the stack
is empty. While this is happening you are able to add other
buffers to the top of the stack. This schem is implemented in module
ruli.
So, here is all necessary to deal with an individual buffer.
For Lists A. Reitsma's lld package will be used. This package
identifies a list by an integer handle.
Mark Koennecke, January 1996
copyright: see implementation file
----------------------------------------------------------------------------*/
#ifndef RUENBUFFER
#define RUENBUFFER
typedef struct {
pObjectDescriptor pDes; /* needed */
char *name; /* BufferName */
int iLineList; /* Handle to the Line List */
} RuenBuffer, *pRuenBuffer;
/*--------------------- live & death ----------------------------------- */
pRuenBuffer CreateRuenBuffer(char *name);
void DeleteRuenBuffer(void *pSelf);
pRuenBuffer CopyRuenBuffer(pRuenBuffer pOld, char *NewName);
/*--------------------- operations --------------------------------------*/
int BufferAppendLine(pRuenBuffer self, char *line);
int BufferDel(pRuenBuffer self, int iLine);
/*
deletes line iLine from the RuenBuffer self
-------------------------------------------------------------------------*/
int BufferInsertAfter(pRuenBuffer self, int iLine, char *line);
/*
inserts line line AFTER line number iLine in the RuenBuffer self
------------------------------------------------------------------------- */
int BufferPrint(pRuenBuffer self, SConnection *pCon);
/*
lists the contents of the RuenBuffer on the Connection pCon
------------------------------------------------------------------------ */
int BufferReplace(pRuenBuffer self, char *pattern, char *pReplace);
/*
replaces all occurences of the string pattern in the whole RuenBuffer
by the replacement string pReplace.
------------------------------------------------------------------------- */
int BufferRun(pRuenBuffer self, SConnection *pCon, SicsInterp *pSics);
/*
executes the lines of the Ruenbuffer one by one.
Returns 1 on success, 0 on error.
------------------------------------------------------------------------- */
int BufferSave(pRuenBuffer self, char *file);
/*
writes the contents of Ruenbuffer self to the file specified by
file.
Returns 1 on success, 0 on error.
--------------------------------------------------------------------------*/
int BufferLoad(pRuenBuffer self, char *file);
/*
reads the contents of file into the RuenBuffer self.
Returns 1 on success, 0 on error.
*/
/* ------------------------ object functions ----------------------------*/
int InitBufferSys(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int BufferCommand(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int BufferAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/* ----------------------- utility --------------------------------------*/
pRuenBuffer FindRuenBuffer(SicsInterp *pSics, char *name);
/*
similar to FindCommand in SCinter.h. But checks the object found if
it is a RuenBuffer.
Returns NULL if no RuenBuffer with this name could be found.
Returns a pointer to the RuenBuffer, when a RuenBuffer of this
name could be found in the interpreter pSics
----------------------------------------------------------------------------*/
#endif

29
build Executable file
View File

@ -0,0 +1,29 @@
#!/bin/sh
#---------------------------------------------------------------------------
# build SICS from Scratch
#
# Mark Koennecke, September 2000
#--------------------------------------------------------------------------
#----- build hardsup
cd hardsup
make
cd ..
#------- build tecs
cd tecs
make
cd ..
#----- build difrac
#cd difrac
#make
#cd ..
#
#---- build matrix
cd matrix
make
cd ..
#------- finally build SICS
make

370
callback.c Normal file
View File

@ -0,0 +1,370 @@
/*--------------------------------------------------------------------------
S I C S C A L L B A C K
Functions needed to deal with the SICSCallback interface. Description is
in file interface.h, interface.w and interface.w.
Mark Koennecke, Juli 1997
Added ScriptCallback, Mark Koennecke, June 2003
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <tcl.h>
#include "fortify.h"
#include "lld.h"
#include "sics.h"
#include "macro.h"
#define CALLBACK 17777
/*--------------------- The interface datastructure ---------------------*/
typedef struct __ICallBack {
int iID;
int iList;
} ICallBack;
/*-------------- The data stored for a single callback ------------------*/
typedef struct {
long iID;
SICSCallBack pFunc;
void *pUserData;
KillFuncIT pKill;
int iEvent;
} CallBackItem, *pCallBackItem;
/*------------------------------------------------------------------------*/
static int CheckPointer(pICallBack self)
{
if(self == NULL) return 0;
if(self->iID != CALLBACK)
{
return 0;
}
return 1;
}
/*-------------------------------------------------------------------------*/
pICallBack CreateCallBackInterface(void)
{
pICallBack pNew = NULL;
pNew = (pICallBack)malloc(sizeof(ICallBack));
if(!pNew)
{
return 0;
}
pNew->iID = CALLBACK;
pNew->iList = LLDcreate(sizeof(CallBackItem));
if(pNew->iList < 0)
{
free(pNew);
return NULL;
}
return pNew;
}
/*--------------------------------------------------------------------------*/
void DeleteCallBackInterface(pICallBack self)
{
int iRet;
CallBackItem sItem;
if(!CheckPointer(self))
{
return;
}
/* kill all userdata associated with callbacks */
iRet = LLDnodePtr2First(self->iList);
while(iRet != 0)
{
LLDnodeDataTo(self->iList,&sItem);
if(sItem.pKill != NULL)
{
sItem.pKill(sItem.pUserData);
}
iRet = LLDnodePtr2Next(self->iList);
}
LLDdelete(self->iList);
free(self);
}
/*--------------------------------------------------------------------------*/
int InvokeCallBack(pICallBack self, int iEvent, void *pEventData)
{
CallBackItem sItem;
int iCurrent, iRet;
int iResult = 1;
if(!CheckPointer(self))
{
return 0;
}
iCurrent = LLDnodePtr2First(self->iList);
while(iCurrent != 0)
{
LLDnodeDataTo(self->iList,&sItem);
if(sItem.iEvent == iEvent)
{
iRet = sItem.pFunc(iEvent, pEventData,sItem.pUserData);
if(!iRet)
{
iResult = 0;
}
}
iCurrent = LLDnodePtr2Next(self->iList);
}
return iResult;
}
/*--------------------------------------------------------------------------*/
static long lCount = 1L;
long RegisterCallback(pICallBack self, int iEvent,
SICSCallBack pFunc,
void *pUserData, KillFunc pKFunc)
{
CallBackItem sItem;
if(!CheckPointer(self))
{
return 0;
}
sItem.iID = lCount++;
assert(pFunc);
sItem.pFunc = pFunc;
sItem.iEvent = iEvent;
sItem.pUserData = pUserData;
sItem.pKill = pKFunc;
LLDnodeAppendFrom(self->iList,&sItem);
return sItem.iID;
}
/*-------------------------------------------------------------------------*/
int RemoveCallback(pICallBack self, long lID)
{
CallBackItem sItem;
int iCurrent;
if(!CheckPointer(self))
{
return 0;
}
iCurrent = LLDnodePtr2First(self->iList);
while(iCurrent != 0)
{
LLDnodeDataTo(self->iList,&sItem);
if(sItem.iID == lID)
{
if(sItem.pKill != NULL)
{
sItem.pKill(sItem.pUserData);
}
LLDnodeDelete(self->iList);
return 1;
}
iCurrent = LLDnodePtr2Next(self->iList);
}
return 0;
}
/*--------------------------------------------------------------------------*/
int RemoveCallback2(pICallBack self, void *pUserData)
{
CallBackItem sItem;
int iCurrent;
if(!CheckPointer(self))
{
return 0;
}
iCurrent = LLDnodePtr2First(self->iList);
while(iCurrent != 0)
{
LLDnodeDataTo(self->iList,&sItem);
if(sItem.pUserData == pUserData)
{
if(sItem.pKill != NULL)
{
sItem.pKill(sItem.pUserData);
}
LLDnodeDelete(self->iList);
}
iCurrent = LLDnodePtr2Next(self->iList);
}
return 1;
}
/*-------------------------------------------------------------------
a write function for the connection which writes to stdout
-------------------------------------------------------------------*/
static int CallbackWrite(SConnection *pCon,char *message, int outCode)
{
if(outCode >= eWarning)
{
fputs(message,stdout);
fputs("\n",stdout);
}
return 1;
}
/*-----------------------------------------------------------------------
the actual callback function invoking the script
------------------------------------------------------------------------*/
static int ScriptCallback(int iEvent, void *pEventData, void *pUserData)
{
SConnection *pCon = NULL;
Tcl_Interp *pTcl;
int status;
pCon = SCCreateDummyConnection(pServ->pSics);
if(!pCon)
{
fprintf(stdout,"ERROR: failed to create dummy connection\n");
return 0;
}
if(pUserData == NULL)
{
fprintf(stdout,"ERROR: ScriptCallback: no script to execute\n");
return 0;
}
SCSetWriteFunc(pCon,CallbackWrite);
MacroPush(pCon);
pTcl = InterpGetTcl(pServ->pSics);
status = Tcl_GlobalEval(pTcl,(char *)pUserData);
if(status != TCL_OK)
{
fprintf(stdout,"ERROR: in CallbackScript: %s\n",(char *)pUserData);
fprintf(stdout,"Tcl-error: %s\n",pTcl->result);
}
MacroPop();
SCDeleteConnection(pCon);
return 1;
}
/*------------------------------------------------------------------------*/
int CallbackScript(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
long lID;
int iEvent, status;
pICallBack pCall = NULL;
CommandList *pCom = NULL;
char pBuffer[132];
if(argc < 2)
{
SCWrite(pCon,"ERROR: insufficient number of arguments to callbackScript",
eError);
return 0;
}
/*
only managers may do this
*/
if(!SCMatchRights(pCon,usMugger))
{
return 0;
}
strtolower(argv[1]);
if(strcmp(argv[1],"connect") == 0)
{
if(argc < 5)
{
SCWrite(pCon,"ERROR: not enough arguments to CallbackScript connect",
eError);
return 0;
}
strtolower(argv[2]);
pCom = FindCommand(pSics,argv[2]);
if(!pCom)
{
SCWrite(pCon,"ERROR: object to connect to not found",eError);
return 0;
}
pCall = GetCallbackInterface(pCom->pData);
if(!pCall)
{
SCWrite(pCon,"ERROR: object has no callback interface",eError);
return 0;
}
iEvent = Text2Event(argv[3]);
if(iEvent < 0)
{
SCWrite(pCon,"ERROR: event type not known",eError);
return 0;
}
lID = RegisterCallback(pCall,iEvent,ScriptCallback,
strdup(argv[4]),free);
sprintf(pBuffer,"callback = %ld", lID);
SCWrite(pCon,pBuffer,eValue);
return 1;
}
else if(strcmp(argv[1],"remove") == 0)
{
if(argc < 4)
{
SCWrite(pCon,"ERROR: not enough arguments to CallbackScript remove",
eError);
return 0;
}
strtolower(argv[2]);
pCom = FindCommand(pSics,argv[2]);
if(!pCom)
{
SCWrite(pCon,"ERROR: object to remove to not found",eError);
return 0;
}
pCall = GetCallbackInterface(pCom->pData);
if(!pCall)
{
SCWrite(pCon,"ERROR: object has no callback interface",eError);
return 0;
}
status = Tcl_GetInt(InterpGetTcl(pSics),argv[3],&iEvent);
if(status != TCL_OK)
{
SCWrite(pCon,"ERROR: failed to convert callback ID to int",eError);
return 0;
}
RemoveCallback(pCall,(long)iEvent);
SCSendOK(pCon);
return 1;
}
SCWrite(pCon,"ERROR: subcommand to CallbackScript not known",eError);
return 0;
}

79
center.tex Normal file
View File

@ -0,0 +1,79 @@
\subsection{Fit and Center}
This is a fit routine for SICS. It takes a scan and tries to find a peak and
its position. Trials showed that fitting a gauss function is not robust
enough for this facility which has to cope with bizarre peak shapes, half
finished measurements and the like. The algorithm choosen tries to find the
center of gravity of the peak. It does this by searching for the maximum
point in the diagram first. Then the points where the peak is below
half maximum are searched for either side of the peak. Within these
limits the COG is calculated. When this is done fit will print some
info about the peak.
Center will the drive the scan variable to the COG of the peak.
The interface to this simple facility is simple:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$fitinter {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __FitCenter *pFit;@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
\mbox{}\verb@ pFit CreateFitCenter(pScanData pScan);@\\
\mbox{}\verb@ void DeleteFitCenter(void *pData);@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int CalculateFit(pFit self);@\\
\mbox{}\verb@ /* @\\
\mbox{}\verb@ CalcluateFit returns: -1 when left FWHM could not be found@\\
\mbox{}\verb@ -2 when right FWHM could not be found@\\
\mbox{}\verb@ 1 on success@\\
\mbox{}\verb@ */@\\
\mbox{}\verb@ int CalculateFitFromData(pFit self, float fAxis[], long lSum[], @\\
\mbox{}\verb@ int iLen);@\\
\mbox{}\verb@ void GetFitResults(pFit self, float *fNewCenter, float *fStdDev,@\\
\mbox{}\verb@ float *FWHM, float *fMax);@\\
\mbox{}\verb@ int DriveCenter(pFit self, SConnection *pCon, SicsInterp *pSics);@\\
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int FitFactory(SConnection *pCon,SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int FitWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int CenterWrapper(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{scrap2}
\verb@"fitcenter.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@ F I T C E N T E R@\\
\mbox{}\verb@@\\
\mbox{}\verb@ A simple peak finding and center of gravity determination facility for@\\
\mbox{}\verb@ SICS.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see copyright.h@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, October 1997@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSFITCENTER@\\
\mbox{}\verb@#define SICSFITCENTER@\\
\mbox{}\verb@@$\langle$fitinter {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

58
center.w Normal file
View File

@ -0,0 +1,58 @@
\subsection{Fit and Center}
This is a fit routine for SICS. It takes a scan and tries to find a peak and
its position. Trials showed that fitting a gauss function is not robust
enough for this facility which has to cope with bizarre peak shapes, half
finished measurements and the like. The algorithm choosen tries to find the
center of gravity of the peak. It does this by searching for the maximum
point in the diagram first. Then the points where the peak is below
half maximum are searched for either side of the peak. Within these
limits the COG is calculated. When this is done fit will print some
info about the peak.
Center will the drive the scan variable to the COG of the peak.
The interface to this simple facility is simple:
@d fitinter @{
typedef struct __FitCenter *pFit;
/*--------------------------------------------------------------------------*/
pFit CreateFitCenter(pScanData pScan);
void DeleteFitCenter(void *pData);
/*-------------------------------------------------------------------------*/
int CalculateFit(pFit self);
/*
CalcluateFit returns: -1 when left FWHM could not be found
-2 when right FWHM could not be found
1 on success
*/
int CalculateFitFromData(pFit self, float fAxis[], long lSum[],
int iLen);
void GetFitResults(pFit self, float *fNewCenter, float *fStdDev,
float *FWHM, float *fMax);
int DriveCenter(pFit self, SConnection *pCon, SicsInterp *pSics);
/*-------------------------------------------------------------------------*/
int FitFactory(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int FitWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int CenterWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,
int argc, char *argv[]);
@}
@o fitcenter.h @{
/*---------------------------------------------------------------------------
F I T C E N T E R
A simple peak finding and center of gravity determination facility for
SICS.
copyright: see copyright.h
Mark Koennecke, October 1997
----------------------------------------------------------------------------*/
#ifndef SICSFITCENTER
#define SICSFITCENTER
@<fitinter@>
#endif
@}

511
chadapter.c Normal file
View File

@ -0,0 +1,511 @@
/*-------------------------------------------------------------------------
C h o c o A d a p t e r
This is a drivable adapter for the ChopperController object (or also generic
controller object). It allows to modify one of the variables supported by
the controller through the normal SICS drive command. For more information
see file choco.w or choco.tex.
Mark Koennecke, January 1998
---------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <tcl.h>
#include "fortify.h"
#include "sics.h"
#define CHOCOINTERNAL
#include "choco.h"
#include "evcontroller.h"
#include "evdriver.i"
#define CHADAINTERNAL
#include "chadapter.h"
#define NOTIMPLEMENTED -11555
/*-------------------------------------------------------------------------*/
static void *AdapterGetInterface(void *pData, int iID)
{
pCHAdapter self = NULL;
self = (pCHAdapter)pData;
assert(self);
if(iID == DRIVEID)
{
return self->pInt;
}
return NULL;
}
/*-------------------------------------------------------------------------*/
static int CHHalt(void *pData)
{
pCHAdapter self = NULL;
self = (pCHAdapter)pData;
assert(self);
self->pDriv->Halt(self->pDriv);
return 1;
}
/*-------------------------------------------------------------------------*/
static int CHLimits(void *pData, float fVal, char *error, int iErrlen)
{
pCHAdapter self = NULL;
self = (pCHAdapter)pData;
assert(self);
if(fVal < self->fLower)
{
strncpy(error,"Lower limit violated",iErrlen);
return 0;
}
if(fVal > self->fUpper)
{
strncpy(error,"Upper limit violated",iErrlen);
return 0;
}
return 1;
}
/*------------------------------------------------------------------------*/
static float CHGetValue(void *pData, SConnection *pCon)
{
pCHAdapter self = NULL;
float fVal;
int iRet;
char pBueffel[80];
self = (pCHAdapter)pData;
assert(self);
iRet = self->pDriv->GetPar(self->pDriv,self->pParName,pBueffel,79);
if(!iRet)
{
fVal = -9999999.99;
self->pDriv->GetError(self->pDriv,&iRet,pBueffel,79);
SCWrite(pCon,pBueffel,eError);
return fVal;
}
sscanf(pBueffel,"%f",&fVal);
return fVal;
}
/*-----------------------------------------------------------------------*/
static int CHStatus(void *pData, SConnection *pCon)
{
pCHAdapter self = NULL;
int iRet, iCode;
static int iRetry = 0;
char pBueffel[80], pError[132];
self = (pCHAdapter)pData;
assert(self);
iRet = self->pDriv->CheckPar(self->pDriv,self->pParName);
switch(iRet)
{
case OKOK:
case HWIdle:
iRetry = 0;
return HWIdle;
case HWFault:
self->pDriv->GetError(self->pDriv,&iCode,pBueffel,79);
iRet = self->pDriv->TryFixIt(self->pDriv,iCode);
sprintf(pError,"ERROR: %s",pBueffel);
SCWrite(pCon,pError,eError);
if(iRet == CHFAIL || iRetry >= 3)
{
iRetry = 0;
return HWFault;
}
else
{
iRetry++;
self->pDriv->SetPar(self->pDriv,self->pParName,
self->fTarget);
return HWBusy;
}
break;
case HWBusy:
return HWBusy;
}
return HWFault;
}
/*-------------------------------------------------------------------------*/
static long CHSetValue(void *pData, SConnection *pCon, float fValue)
{
pCHAdapter self = NULL;
char pBueffel[80], pError[132];
int iRet, iCode, i;
self = (pCHAdapter)pData;
assert(self);
/* check privilege */
if(!SCMatchRights(pCon,usUser))
{
SCWrite(pCon,"ERROR: Insufficient privilege for driving",eError);
return 0;
}
for(i = 0; i < 3; i++)
{
iRet = self->pDriv->SetPar(self->pDriv,self->pParName,fValue);
if(iRet)
{
self->fTarget = fValue;
return 1;
}
self->pDriv->GetError(self->pDriv,&iCode,pBueffel,79);
sprintf(pError,"ERROR: %s",pBueffel);
SCWrite(pCon,pError,eError);
iRet = self->pDriv->TryFixIt(self->pDriv,iCode);
if(iRet == CHFAIL)
return 0;
}
return 0;
}
/*------------------------------------------------------------------------*/
static void KillAdapter(void *pData)
{
pCHAdapter self = NULL;
self = (pCHAdapter)pData;
if(!self)
return;
if(self->pDes)
DeleteDescriptor(self->pDes);
if(self->pInt)
free(self->pInt);
if(self->pParName);
free(self->pParName);
free(self);
}
/*-----------------------------------------------------------------------
Syntax: ChopperAdapter name choppercontroller parname upper lower
*/
int CHAdapterFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
char pBueffel[256];
pCHAdapter pNew = NULL;
pChoco pChopper = NULL;
CommandList *pCom = NULL;
pDummy pDum = NULL;
double dUpper, dLower;
int iRet;
/* do we have enough arguments? */
if(argc < 6)
{
SCWrite(pCon,
"ERROR: Insufficient number of arguments to ChopperAdapter",
eError);
return 0;
}
/* find the chopper first */
pCom = FindCommand(pSics,argv[2]);
if(pCom)
{
pDum = (pDummy)pCom->pData;
if(pDum)
{
if(strcmp(pDum->pDescriptor->name,"Chopper") == 0)
{
pChopper = (pChoco)pCom->pData;
}
}
}
if(!pChopper)
{
sprintf(pBueffel,"ERROR: %s is NO chopper controller",
argv[3]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* interpret limits */
iRet = Tcl_GetDouble(pSics->pTcl,argv[5],&dUpper);
if(iRet != TCL_OK)
{
sprintf(pBueffel,
"ERROR: expected numeric argument for upper limit, got %s",
argv[4]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetDouble(pSics->pTcl,argv[4],&dLower);
if(iRet != TCL_OK)
{
sprintf(pBueffel,
"ERROR: expected numeric argument for lower limit, got %s",
argv[5]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* allocate new adapter data structure */
pNew = (pCHAdapter)malloc(sizeof(CHAdapter));
if(!pNew)
{
SCWrite(pCon,"ERROR: out of memory in ChopperAdapter",eError);
return 0;
}
memset(pNew,0,sizeof(CHAdapter));
pNew->pDes = CreateDescriptor("ChopperAdapter");
pNew->pDriv = CHGetDriver(pChopper);
pNew->pInt = CreateDrivableInterface();
pNew->pParName = strdup(argv[3]);
if( !pNew->pDes || !pNew->pDriv || !pNew->pInt || !pNew->pParName)
{
SCWrite(pCon,"ERROR: out of memory in ChopperAdapter",eError);
return 0;
}
/* initialize other fields */
pNew->fTarget = 0.;
pNew->fLower = (float)dLower;
pNew->fUpper = (float)dUpper;
pNew->pDes->GetInterface = AdapterGetInterface;
pNew->pInt->Halt = CHHalt;
pNew->pInt->CheckLimits = CHLimits;
pNew->pInt->SetValue = CHSetValue;
pNew->pInt->CheckStatus = CHStatus;
pNew->pInt->GetValue = CHGetValue;
/* install command */
iRet = AddCommand(pSics, argv[1],CHAdapterAction,KillAdapter,pNew);
if(!iRet)
{
sprintf(pBueffel,
"ERROR: duplicate ChopperAdapter command %s NOT created",
argv[1]);
SCWrite(pCon,pBueffel,eError);
KillAdapter(pNew);
return 0;
}
return 1;
}
/*------------------------------------------------------------------------*/
int CHAdapterAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pCHAdapter self = NULL;
int iRet;
char pBueffel[132];
float fValue;
self = (pCHAdapter)pData;
assert(self);
/* only action: get value */
fValue = CHGetValue(self,pCon);
if(fValue < -99000)
{
return 0;
}
else
{
sprintf(pBueffel,"%s = %f",argv[0],fValue);
SCWrite(pCon,pBueffel,eValue);
}
return 1;
}
/*=========================================================================
An environment driver based on top of a controller object.
-------------------------------------------------------------------------*/
static int AVEVSetValue(pEVDriver self, float fNew)
{
pCHev myData;
assert(self);
myData = (pCHev)self->pPrivate;
assert(myData);
myData->iLastError = 0;
return myData->pDriv->SetPar(myData->pDriv,myData->pParName,fNew);
}
/*-----------------------------------------------------------------------*/
static int AVEVGetValue(pEVDriver self, float *fNew)
{
pCHev myData;
int iRet;
char pBueffel[80];
assert(self);
myData = (pCHev)self->pPrivate;
assert(myData);
iRet = myData->pDriv->GetPar(myData->pDriv,myData->pParName,
pBueffel,79);
sscanf(pBueffel,"%f",fNew);
return iRet;
}
/*-----------------------------------------------------------------------*/
static int AVEVSend(pEVDriver self, char *pCommand,
char *pReply, int iLen)
{
pCHev myData;
assert(self);
myData = (pCHev)self->pPrivate;
assert(myData);
myData->iLastError = NOTIMPLEMENTED;
return 0;
}
/*-----------------------------------------------------------------------*/
static int AVEVGetError(pEVDriver self, int *iCode,
char *pReply, int iLen)
{
pCHev myData;
assert(self);
myData = (pCHev)self->pPrivate;
assert(myData);
if(myData->iLastError == NOTIMPLEMENTED)
{
strncpy(pReply,"ERROR: Not Implemented here!", iLen);
*iCode = NOTIMPLEMENTED;
myData->iLastError = 0;
return 1;
}
else
{
return myData->pDriv->GetError(myData->pDriv, iCode,
pReply, iLen);
}
}
/*------------------------------------------------------------------------*/
static int AVEVTryFixIt(pEVDriver self, int iCode)
{
pCHev myData;
assert(self);
myData = (pCHev)self->pPrivate;
assert(myData);
if(iCode == NOTIMPLEMENTED)
{
return DEVFAULT;
}
else
{
return myData->pDriv->TryFixIt(myData->pDriv, iCode);
}
}
/*---------------------------------------------------------------------*/
static int AVEVInit(pEVDriver self)
{
pCHev myData;
assert(self);
myData = (pCHev)self->pPrivate;
assert(myData);
return myData->pDriv->Init(myData->pDriv);
}
/*---------------------------------------------------------------------*/
static int AVEVClose(pEVDriver self)
{
pCHev myData;
assert(self);
myData = (pCHev)self->pPrivate;
assert(myData);
return myData->pDriv->Close(myData->pDriv);
}
/*----------------------------------------------------------------------*/
static void AVEVKillPrivate(void *pData)
{
pCHev myData;
if(pData != NULL)
{
myData = (pCHev)pData;
if(myData != NULL)
{
if(myData->pParName)
free(myData->pParName);
free(myData);
}
}
}
/*---------------------------------------------------------------------*/
pEVDriver MakeControllerEnvironmentDriver(int argc, char *argv[])
{
pEVDriver pNew = NULL;
pCHev myData = NULL;
CommandList *pCom = NULL;
pDummy pDum = NULL;
pChoco pChop;
/*
Two arguments are needed: the name of the controller and the
name of the parameter
*/
if(argc < 2)
{
return NULL;
}
pCom = FindCommand(pServ->pSics,argv[0]);
if(!pCom)
{
return NULL;
}
pDum = pCom->pData;
if(!pDum)
{
return NULL;
}
if(strcmp(pDum->pDescriptor->name,"Chopper") != 0)
{
return NULL;
}
/* alright: I think we got a controller now, let us create our
act
*/
pNew = CreateEVDriver(argc,argv);
if(!pNew)
{
return NULL;
}
myData = (pCHev)malloc(sizeof(CHev));
if(!myData)
{
return NULL;
}
pChop = (pChoco)pCom->pData;
myData->iLastError = 0;
myData->pDriv = pChop->pDriv;
myData->pParName = strdup(argv[1]);
pNew->pPrivate = myData;
pNew->SetValue =AVEVSetValue;
pNew->GetValue =AVEVGetValue;
pNew->Send = AVEVSend;
pNew->GetError =AVEVGetError;
pNew->TryFixIt =AVEVTryFixIt;
pNew->Init =AVEVInit;
pNew->Close =AVEVClose;
pNew->KillPrivate =AVEVKillPrivate;
return pNew;
}

47
chadapter.h Normal file
View File

@ -0,0 +1,47 @@
/*------------------------------------------------------------------------
C H a d a p t e r
This is the header file for a drive adapter for collaboration with a
general device controller as implemented in choco.*
Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef SICSCHADA
#define SICSCHADA
#include "codri.h"
typedef struct __CHADAPTER *pCHAdapter;
/*-----------------------------------------------------------------------*/
int CHAdapterFactory(SConnection *pCon, SicsInterp *pSics,
void *pData,
int argc, char *argv[]);
int CHAdapterAction(SConnection *pCon, SicsInterp *pSics,
void *pData,
int argc, char *argv[]);
pEVDriver MakeControllerEnvironmentDriver(int argc, char *argv[]);
#ifdef CHADAINTERNAL
typedef struct __CHADAPTER {
pObjectDescriptor pDes;
pCodri pDriv;
pIDrivable pInt;
float fUpper;
float fLower;
float fTarget;
char *pParName;
}CHAdapter;
typedef struct __CHEV {
char *pParName;
pCodri pDriv;
int iLastError;
}CHev, *pCHev;
#endif
#endif

311
choco.c Normal file
View File

@ -0,0 +1,311 @@
/*------------------------------------------------------------------------
C h o p p e r C o n t r o l l e r
Implementation file for the SICS chopper controller and general controller
device. For details about this object and its relation with the SICS system
see choco.w or choco.tex.
Mark Koennecke, January 1998
-------------------------------------------------------------------------*/
#include <stdlib.h>
#include <tcl.h>
#include <assert.h>
#include "fortify.h"
#include "sics.h"
#define CHOCOINTERNAL
#include "choco.h"
/*------------------------------------------------------------------------*/
int CHGetParameter(pChoco self, char *parname, char *pParValue,
int iBuflen)
{
int iRet, iCode;
assert(self);
iRet = self->pDriv->GetPar(self->pDriv, parname, pParValue,
iBuflen);
if(!iRet)
{
iRet = 0;
self->pDriv->GetError(self->pDriv,&iCode,pParValue, iBuflen);
}
return iRet;
}
/*------------------------------------------------------------------------*/
pCodri CHGetDriver(pChoco self)
{
assert(self);
return self->pDriv;
}
/*------------------------------------------------------------------------*/
int CHList(pChoco self, SConnection *pCon, char *name)
{
char *pPar, *pCopy = NULL;
char pValue[80];
char pMessage[256];
int iRet, iLen;
Tcl_DString tlist;
assert(self);
/* copy pParList as it will be destroyed by strtok */
iLen = strlen(self->pDriv->pParList);
pCopy = (char *)malloc((iLen+10)*sizeof(char));
if(!pCopy)
{
SCWrite(pCon,"ERROR: out of memory in CHList",eError);
return 0;
}
memset(pCopy,0,iLen+10);
strcpy(pCopy,self->pDriv->pParList);
Tcl_DStringInit(&tlist);
pPar = strtok(pCopy,",");
while(pPar != NULL)
{
iRet = CHGetParameter(self,pPar,pValue,79);
if(iRet)
{
sprintf(pMessage,"%s.%s = %s \n",name,pPar,pValue);
}
else
{
sprintf(pMessage,"ERROR: %s : while reading parameter %s \n",
pValue,pPar);
}
Tcl_DStringAppend(&tlist, pMessage,-1);
pPar = strtok(NULL,",");
}
SCWrite(pCon,Tcl_DStringValue(&tlist),eValue);
Tcl_DStringFree(&tlist);
free(pCopy);
return 1;
}
/*-----------------------------------------------------------------------*/
int ChocoAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pChoco self = NULL;
char pValue[80], pMessage[256];
int iRet;
self = (pChoco)pData;
assert(self);
if(argc < 2)
{
sprintf(pMessage, "ERROR: Ragument required for %s",argv[0]);
SCWrite(pCon,pMessage,eError);
return 0;
}
/* argument can either be list or parameter name */
strtolower(argv[1]);
if(strcmp(argv[1],"list") == 0)
{
return CHList(self,pCon,argv[0]);
}
else
{
if(argc > 2)
{
/* set case */
iRet = self->pDriv->SetPar2(self->pDriv,argv[1],argv[2]);
if(!iRet)
{
self->pDriv->GetError(self->pDriv,&iRet,pValue,79);
sprintf(pMessage,"ERROR: %s",pValue);
SCWrite(pCon,pMessage,eError);
return 0;
}
else
{
SCSendOK(pCon);
return 1;
}
}
else
{
/* get case */
iRet = CHGetParameter(self,argv[1],pValue,79);
if(iRet)
{
sprintf(pMessage,"%s.%s = %s",argv[0],argv[1],pValue);
}
else
{
sprintf(pMessage,"ERROR: %s : while reading parameter %s",
pValue,argv[1]);
}
SCWrite(pCon,pMessage,eValue);
return iRet;
}
}
return 0;
}
/*----------------------------------------------------------------------*/
static void KillChoco(void *pData)
{
pChoco self = NULL;
self = (pChoco)pData;
if(!self)
return;
if(self->pDriv)
{
self->pDriv->Close(self->pDriv);
self->pDriv->Delete(self->pDriv);
if(self->pDriv->pParList)
free(self->pDriv->pParList);
free(self->pDriv);
}
if(self->pDes)
DeleteDescriptor(self->pDes);
free(self);
}
/*-----------------------------------------------------------------------
DRIVERS
*/
extern pCodri MakeSimChopper(void);
extern pCodri MakeDoChoDriver(char *pHost, int iPort, int iChannel,
int iSingle);
extern pCodri MakeCookerDriver(char *pHost, int iPort, int iChannel);
/*-----------------------------------------------------------------------*/
int ChocoFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pChoco pNew = NULL;
pCodri pDriv = NULL;
pObjectDescriptor pDes = NULL;
char pBueffel[132];
int iRet, iPort, iChannel;
int iSingle = 0;
if(argc < 3)
{
SCWrite(pCon,
"ERROR: Insufficient number of arguments to MakeController",
eError);
return 0;
}
/* first try to get everything done */
pNew = (pChoco)malloc(sizeof(Choco));
pDes = CreateDescriptor("Chopper");
/* do driver */
strtolower(argv[2]);
if(strcmp(argv[2],"sim") == 0)
{
pDriv = MakeSimChopper();
}
else if(strcmp(argv[2],"docho") == 0)
{
if(argc < 6)
{
SCWrite(pCon,
"ERROR: Insufficient number of arguments to install Dornier Chopper driver",
eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[4],&iPort);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: expected integer as port number, got %s",
argv[4]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[5],&iChannel);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: expected integer as channel number, got %s",
argv[4]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
if(argc > 6)
{
iRet = Tcl_GetInt(pSics->pTcl,argv[6],&iSingle);
if(iRet != TCL_OK)
{
sprintf(pBueffel,
"ERROR: expected integer as single flag, got %s",
argv[6]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
}
pDriv = MakeDoChoDriver(argv[3],iPort,iChannel,iSingle);
}
else if(strcmp(argv[2],"sanscook") == 0)
{
if(argc < 6)
{
SCWrite(pCon,
"ERROR: Insufficient number of arguments to install SANS Cooker driver",
eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[4],&iPort);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: expected integer as port number, got %s",
argv[4]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = Tcl_GetInt(pSics->pTcl,argv[5],&iChannel);
if(iRet != TCL_OK)
{
sprintf(pBueffel,"ERROR: expected integer as channel number, got %s",
argv[4]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
pDriv = MakeCookerDriver(argv[3],iPort,iChannel);
}
else
{
sprintf(pBueffel,"ERROR: Driver %s NOT supported for MakeController",
argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
if( (pNew == NULL) || (pDes == NULL) || (pDriv == NULL) )
{
SCWrite(pCon,"ERROR: No memory left to create controller",eError);
return 0;
}
pNew->pDes = pDes;
pNew->pDriv = pDriv;
/* initialize driver */
iRet = pDriv->Init(pDriv);
if(!iRet)
{
SCWrite(pCon,"ERROR: Failed to initialize driver",eError);
KillChoco(pNew);
return 0;
}
/* install as command */
iRet = AddCommand(pSics, argv[1],ChocoAction,KillChoco,pNew);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate command %s NOT created",
argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
return 1;
}

36
choco.h Normal file
View File

@ -0,0 +1,36 @@
/*-----------------------------------------------------------------------
C h o p p e r C o n t r o l l e r
This is both the header file for a general controller and a SICS
chopper controller.
Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef CHOCOSICS
#define CHOCOSICS
#include "codri.h"
typedef struct __CHOCO *pChoco;
/*------------------------------------------------------------------------*/
int CHGetParameter(pChoco self, char *pParName,
char *pParValue, int iBuflen);
pCodri CHGetDriver(pChoco self);
int CHList(pChoco self, SConnection *pCon, char *name);
/*------------------------------------------------------------------------*/
int ChocoAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int ChocoFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#ifdef CHOCOINTERNAL
typedef struct __CHOCO {
pObjectDescriptor pDes;
pCodri pDriv;
} Choco;
#endif
#endif

380
choco.tex Normal file
View File

@ -0,0 +1,380 @@
\subsection{Chopper Controller}
Yet another way to deal with a controller has been devised for
SICS. This uses the concept of a general controller which can have
parameters enquired and set. Furthermore it may have parameters which
may be driven like a motor or environment controller through special
adapters . This scheme is
used for the chopper controller for FOCUS.
\begin{itemize}
\item A driver for a particular controller which allows to set and get
parameters.
\item The general controller object which holds things together.
\item An adapter object which allows to drive special parameters in a general
controller. Such adapter objects can be configured for each drivable parameter
in a controller.
\item An adapter to an environment controller driver.
\end{itemize}
The test case for this way of doing things is a controller for running
choppers. This is why it gets the name.
The chopper system in question is the FOCUS chopper system. There are two
choppers, a fermi chopper and a disk chopper. This system can be run in two
different modes: In synchronous mode both choppers run at a
predefined ratio of speeds. For instance the fermi chopper is two
times faster then the disk chopper. This means, that setting a new
value for one chopper also changes the speed of the other chopper. In
asynchronous mode both choppers operate independently. Also the ration
to use for synchronous mode can be changed. Another parameter which
frequently changes is the phase of the two choppers. In order to
compensate for the fligh path between the two choppers there is a
small angular displacement of the choppers against each other which
varies with wavelength.
\subsubsection{The Controller Driver}
The controller driver is represented by the following data structure:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$codri {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __CODRI *pCodri;@\\
\mbox{}\verb@ typedef struct __CODRI {@\\
\mbox{}\verb@ int (*Init)(pCodri self);@\\
\mbox{}\verb@ int (*Close)(pCodri self);@\\
\mbox{}\verb@ int (*Delete)(pCodri self);@\\
\mbox{}\verb@ int (*SetPar)(pCodri self, @\\
\mbox{}\verb@ char *parname,@\\
\mbox{}\verb@ float fValue);@\\
\mbox{}\verb@ int (*SetPar2)(pCodri self, @\\
\mbox{}\verb@ char *parname,@\\
\mbox{}\verb@ char *value);@\\
\mbox{}\verb@ int (*GetPar)(pCodri self,@\\
\mbox{}\verb@ char *parname,@\\
\mbox{}\verb@ char *pBuffer,@\\
\mbox{}\verb@ int iBufLen);@\\
\mbox{}\verb@ int (*CheckPar)(pCodri self, @\\
\mbox{}\verb@ char *parname);@\\
\mbox{}\verb@ int (*GetError)(pCodri self, int *iCode,@\\
\mbox{}\verb@ char *pError, @\\
\mbox{}\verb@ int iErrLen);@\\
\mbox{}\verb@ int (*TryFixIt)(pCodri self, int iCode);@\\
\mbox{}\verb@ int (*Halt)(pCodri self);@\\
\mbox{}\verb@ char *pParList;@\\
\mbox{}\verb@ void *pPrivate;@\\
\mbox{}\verb@ }Codri;@\\
\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}
All functions take a pointer to the controller driver itself as a
parameter. All functions except TryFixIt and CheckPar
return 0 on failure and 1 for success.
\begin{description}
\item[Init] initializes the controller driver. The parameters argc,
argv are main() style parameters for the initialization of the
controller driver.
\item[Close] closes the connection to the controller but does not delete a thing.
\item[Delete] closes the connection to the controller and deletes private data structures. Called when deleting the controller.
\item[SetPar] tries to set the parameter parname to the value
fValue. The last is floating point which covers the frequent
occurence of numeric values.
\item[SetPar2] The same as SetPar but uses test string as input for
parameter setting.
\item[GetPar] retrieves the parameter parname formatted as text. The
value is put into the buffer pBuffer. iBufLen is the maximum number of
bytes permissable for pBuffer.
\item[CheckPar] When parameters are driven a means is needed to find
out about the progress of operations and errors during the
operation. This is done by CheckPar for the parameter parname. The
return value of this function must be one of the HWBusy, HWError,
HWDone family documented in the motor driver object description.
\item[GetError] retrieves the last error. An integer error code is
placed into iCode and a textual description of the problem is written
to pError. Maximum iErrLen bytes are copied to pError.
\item[TryFixIt] tries to fix the error condition specified by iCode in
software if this possible. TryFisIt returns HWRedo if the last command
needs to resent, HWFault if the problem could not be fixed and HWOK if
the error can be ignored or was fully resolved.
\item[pParList] is text string containing a comma separated list of
all parameters understood by this driver.
\item[pPrivate] Is a pointer to a driver specific specific data
structure. This data structure will not be messed with by upper level code.
\end{description}
\subsubsection{The Controller Object}
This is the general controller object visible from the SICS
interpreter. This object allows to list all possible
parameters. Internal functions are provided for setting
parameters. But this is meant to be operated through a drive adapter
object (see below) in SICS. Thus the interface to this object
includes:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$chocoint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __CHOCO *pChoco;@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int CHGetParameter(pChoco self, char *pParName, @\\
\mbox{}\verb@ char *pParValue, int iBuflen); @\\
\mbox{}\verb@ @\\
\mbox{}\verb@ pCodri CHGetDriver(pChoco self);@\\
\mbox{}\verb@ int CHList(pChoco self, SConnection *pCon, char *name);@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ int ChocoAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int ChocoFactory(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{description}
\item[CHGetParameter] retrieves the value of the parameter ParName
converted to text. Maximum iBufLen of result or error text are copied into the
buffer pParvalue.
\item[CHGetDriver] returns a pointer to the controller driver. This
function will be used by the drive adapters for interfacing with the
driver directly.
\item[CHList] prints a listing of all parameters to the client
described by pCon. name is the name of the controller.
\item[ChocoAction] is the SICS interpreter interface function for the
controller.
\item[ChocoFactory] is the SICS interpreter interface function which
installs a controller into SICS.
\end{description}
Most of the actual work of the controller is left to the driver. Thus
the internal data structure for a controller object is very simple:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap3}
$\langle$chocodata {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __CHOCO {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ pCodri pDriv;@\\
\mbox{}\verb@ } Choco;@\\
\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}
It consists just of the standard SICS object descriptor and a pointer
to the driver.
\subsubsection{The Drive And Environment Adapters}
Most of the work of the drive adaptor is hidden in the functions
implementing the drivable interface. Thus the interface to the
DriveAdapter is fairly simple:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
$\langle$adapter {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __CHADAPTER *pCHAdapter;@\\
\mbox{}\verb@/*-----------------------------------------------------------------------*/@\\
\mbox{}\verb@ int CHAdapterFactory(SConnection *pCon, SicsInterp *pSics, @\\
\mbox{}\verb@ void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@ int CHAdapterAction(SConnection *pCon, SicsInterp *pSics, @\\
\mbox{}\verb@ void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@@\\
\mbox{}\verb@ pEVDriver MakeControllerEnvironmentDriver(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{description}
\item[CHAdapterFactory] is the SICS interpreter factory function for
creating a drive adapter.
\item[CHAdapterAction] is the SICS interpreter function for
representing the object in SICS. Just a single action is supported:
request the value of the parameter.
\item[MakeControllerEnvironmentDriver] creates an environment control
driver for a parameter in a general controller object.
\end{description}
The data structure for the drive adapter is slightly more interesting:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap5}
$\langle$adadata {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __CHADAPTER {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ pCodri pDriv;@\\
\mbox{}\verb@ pIDrivable pInt;@\\
\mbox{}\verb@ float fUpper;@\\
\mbox{}\verb@ float fLower;@\\
\mbox{}\verb@ float fTarget;@\\
\mbox{}\verb@ char *pParName;@\\
\mbox{}\verb@ }CHAdapter;@\\
\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{description}
\item[pDes] is the standard object descriptor.
\item[pDriv] is a pointer to the controller driver.
\item[pInt] is a pointer to the drivable interface implemented by the
adapter.
\item[fUpper] upper limit for the parameter.
\item[fLower] lower limit for the parameter.
\item[pParName] is the name of the parameter which is driven through
this adapter.
\end{description}
This is the data structure for the private part of the environment
controller driver:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap6}
$\langle$evada {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __CHEV {@\\
\mbox{}\verb@ char *pParName;@\\
\mbox{}\verb@ pCodri pDriv;@\\
\mbox{}\verb@ int iLastError;@\\
\mbox{}\verb@ }CHev, *pCHev;@\\
\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{scrap7}
\verb@"codri.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ C o n t r o l l e r D r i v e r@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This file contains the description of the data structure for a@\\
\mbox{}\verb@ general controller driver.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, January 1998@\\
\mbox{}\verb@--------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef CODRIV@\\
\mbox{}\verb@#define CODRIV@\\
\mbox{}\verb@#define CHFAIL -1@\\
\mbox{}\verb@#define CHREDO -2@\\
\mbox{}\verb@#define CHOK -3@\\
\mbox{}\verb@@$\langle$codri {\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{scrap8}
\verb@"choco.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-----------------------------------------------------------------------@\\
\mbox{}\verb@ C h o p p e r C o n t r o l l e r@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This is both the header file for a general controller and a SICS@\\
\mbox{}\verb@ chopper controller.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, January 1998@\\
\mbox{}\verb@--------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef CHOCOSICS@\\
\mbox{}\verb@#define CHOCOSICS@\\
\mbox{}\verb@#include "codri.h"@\\
\mbox{}\verb@@$\langle$chocoint {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#ifdef CHOCOINTERNAL@\\
\mbox{}\verb@@$\langle$chocodata {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@#endif @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap9}
\verb@"chadapter.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------@\\
\mbox{}\verb@ C H a d a p t e r@\\
\mbox{}\verb@@\\
\mbox{}\verb@ This is the header file for a drive adapter for collaboration with a@\\
\mbox{}\verb@ general device controller as implemented in choco.*@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, January 1998@\\
\mbox{}\verb@--------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSCHADA@\\
\mbox{}\verb@#define SICSCHADA@\\
\mbox{}\verb@#include "codri.h"@\\
\mbox{}\verb@@$\langle$adapter {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#ifdef CHADAINTERNAL@\\
\mbox{}\verb@@$\langle$adadata {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\langle$evada {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{To Do}
This scheme seems to be quite promising for handling many SICS
objects. The following enhancements could be considered. Allow to set
certain primitive parameters without a drivable interface. And add an
adapter for an environment variable in the controller.

281
choco.w Normal file
View File

@ -0,0 +1,281 @@
\subsection{Chopper Controller}
Yet another way to deal with a controller has been devised for
SICS. This uses the concept of a general controller which can have
parameters enquired and set. Furthermore it may have parameters which
may be driven like a motor or environment controller through special
adapters . This scheme is
used for the chopper controller for FOCUS.
\begin{itemize}
\item A driver for a particular controller which allows to set and get
parameters.
\item The general controller object which holds things together.
\item An adapter object which allows to drive special parameters in a general
controller. Such adapter objects can be configured for each drivable parameter
in a controller.
\item An adapter to an environment controller driver.
\end{itemize}
The test case for this way of doing things is a controller for running
choppers. This is why it gets the name.
The chopper system in question is the FOCUS chopper system. There are two
choppers, a fermi chopper and a disk chopper. This system can be run in two
different modes: In synchronous mode both choppers run at a
predefined ratio of speeds. For instance the fermi chopper is two
times faster then the disk chopper. This means, that setting a new
value for one chopper also changes the speed of the other chopper. In
asynchronous mode both choppers operate independently. Also the ration
to use for synchronous mode can be changed. Another parameter which
frequently changes is the phase of the two choppers. In order to
compensate for the fligh path between the two choppers there is a
small angular displacement of the choppers against each other which
varies with wavelength.
\subsubsection{The Controller Driver}
The controller driver is represented by the following data structure:
@d codri @{
typedef struct __CODRI *pCodri;
typedef struct __CODRI {
int (*Init)(pCodri self);
int (*Close)(pCodri self);
int (*Delete)(pCodri self);
int (*SetPar)(pCodri self,
char *parname,
float fValue);
int (*SetPar2)(pCodri self,
char *parname,
char *value);
int (*GetPar)(pCodri self,
char *parname,
char *pBuffer,
int iBufLen);
int (*CheckPar)(pCodri self,
char *parname);
int (*GetError)(pCodri self, int *iCode,
char *pError,
int iErrLen);
int (*TryFixIt)(pCodri self, int iCode);
int (*Halt)(pCodri self);
char *pParList;
void *pPrivate;
}Codri;
@}
All functions take a pointer to the controller driver itself as a
parameter. All functions except TryFixIt and CheckPar
return 0 on failure and 1 for success.
\begin{description}
\item[Init] initializes the controller driver. The parameters argc,
argv are main() style parameters for the initialization of the
controller driver.
\item[Close] closes the connection to the controller but does not delete a thing.
\item[Delete] closes the connection to the controller and deletes private data structures. Called when deleting the controller.
\item[SetPar] tries to set the parameter parname to the value
fValue. The last is floating point which covers the frequent
occurence of numeric values.
\item[SetPar2] The same as SetPar but uses test string as input for
parameter setting.
\item[GetPar] retrieves the parameter parname formatted as text. The
value is put into the buffer pBuffer. iBufLen is the maximum number of
bytes permissable for pBuffer.
\item[CheckPar] When parameters are driven a means is needed to find
out about the progress of operations and errors during the
operation. This is done by CheckPar for the parameter parname. The
return value of this function must be one of the HWBusy, HWError,
HWDone family documented in the motor driver object description.
\item[GetError] retrieves the last error. An integer error code is
placed into iCode and a textual description of the problem is written
to pError. Maximum iErrLen bytes are copied to pError.
\item[TryFixIt] tries to fix the error condition specified by iCode in
software if this possible. TryFisIt returns HWRedo if the last command
needs to resent, HWFault if the problem could not be fixed and HWOK if
the error can be ignored or was fully resolved.
\item[pParList] is text string containing a comma separated list of
all parameters understood by this driver.
\item[pPrivate] Is a pointer to a driver specific specific data
structure. This data structure shall not be messed with by upper level code.
\end{description}
\subsubsection{The Controller Object}
This is the general controller object visible from the SICS
interpreter. This object allows to list all possible
parameters. Internal functions are provided for setting
parameters. But this is meant to be operated through a drive adapter
object (see below) in SICS. Thus the interface to this object
includes:
@d chocoint @{
typedef struct __CHOCO *pChoco;
/*------------------------------------------------------------------------*/
int CHGetParameter(pChoco self, char *pParName,
char *pParValue, int iBuflen);
pCodri CHGetDriver(pChoco self);
int CHList(pChoco self, SConnection *pCon, char *name);
/*------------------------------------------------------------------------*/
int ChocoAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int ChocoFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
@}
\begin{description}
\item[CHGetParameter] retrieves the value of the parameter ParName
converted to text. Maximum iBufLen of result or error text are copied into the
buffer pParvalue.
\item[CHGetDriver] returns a pointer to the controller driver. This
function will be used by the drive adapters for interfacing with the
driver directly.
\item[CHList] prints a listing of all parameters to the client
described by pCon. name is the name of the controller.
\item[ChocoAction] is the SICS interpreter interface function for the
controller.
\item[ChocoFactory] is the SICS interpreter interface function which
installs a controller into SICS.
\end{description}
Most of the actual work of the controller is left to the driver. Thus
the internal data structure for a controller object is very simple:
@d chocodata @{
typedef struct __CHOCO {
pObjectDescriptor pDes;
pCodri pDriv;
} Choco;
@}
It consists just of the standard SICS object descriptor and a pointer
to the driver.
\subsubsection{The Drive And Environment Adapters}
Most of the work of the drive adaptor is hidden in the functions
implementing the drivable interface. Thus the interface to the
DriveAdapter is fairly simple:
@d adapter @{
typedef struct __CHADAPTER *pCHAdapter;
/*-----------------------------------------------------------------------*/
int CHAdapterFactory(SConnection *pCon, SicsInterp *pSics,
void *pData,
int argc, char *argv[]);
int CHAdapterAction(SConnection *pCon, SicsInterp *pSics,
void *pData,
int argc, char *argv[]);
pEVDriver MakeControllerEnvironmentDriver(int argc, char *argv[]);
@}
\begin{description}
\item[CHAdapterFactory] is the SICS interpreter factory function for
creating a drive adapter.
\item[CHAdapterAction] is the SICS interpreter function for
representing the object in SICS. Just a single action is supported:
request the value of the parameter.
\item[MakeControllerEnvironmentDriver] creates an environment control
driver for a parameter in a general controller object.
\end{description}
The data structure for the drive adapter is slightly more interesting:
@d adadata @{
typedef struct __CHADAPTER {
pObjectDescriptor pDes;
pCodri pDriv;
pIDrivable pInt;
float fUpper;
float fLower;
float fTarget;
char *pParName;
}CHAdapter;
@}
\begin{description}
\item[pDes] is the standard object descriptor.
\item[pDriv] is a pointer to the controller driver.
\item[pInt] is a pointer to the drivable interface implemented by the
adapter.
\item[fUpper] upper limit for the parameter.
\item[fLower] lower limit for the parameter.
\item[pParName] is the name of the parameter which is driven through
this adapter.
\end{description}
This is the data structure for the private part of the environment
controller driver:
@d evada @{
typedef struct __CHEV {
char *pParName;
pCodri pDriv;
int iLastError;
}CHev, *pCHev;
@}
@o codri.h @{
/*-------------------------------------------------------------------------
C o n t r o l l e r D r i v e r
This file contains the description of the data structure for a
general controller driver.
Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef CODRIV
#define CODRIV
#define CHFAIL -1
#define CHREDO -2
#define CHOK -3
@<codri@>
#endif
@}
@o choco.h @{
/*-----------------------------------------------------------------------
C h o p p e r C o n t r o l l e r
This is both the header file for a general controller and a SICS
chopper controller.
Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef CHOCOSICS
#define CHOCOSICS
#include "codri.h"
@<chocoint@>
#ifdef CHOCOINTERNAL
@<chocodata@>
#endif
#endif
@}
@o chadapter.h @{
/*------------------------------------------------------------------------
C H a d a p t e r
This is the header file for a drive adapter for collaboration with a
general device controller as implemented in choco.*
Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef SICSCHADA
#define SICSCHADA
#include "codri.h"
@<adapter@>
#ifdef CHADAINTERNAL
@<adadata@>
@<evada@>
#endif
#endif
@}
\subsubsection{To Do}
This scheme seems to be quite promising for handling many SICS
objects. The following enhancements could be considered. Allow to set
certain primitive parameters without a drivable interface. And add an
adapter for an environment variable in the controller.

122
circular.c Normal file
View File

@ -0,0 +1,122 @@
/*-----------------------------------------------------------------------
Implementation file for a circular buffer facility.
Mark Koennecke, October 1999
-------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include "fortify.h"
#include "circular.h"
/*========================================================================
Definitions of Structures
*/
typedef struct __CircularItem {
void *pData;
struct __CircularItem *next;
struct __CircularItem *previous;
}CircularItem, *pCircularItem;
typedef struct __CIRCULAR {
pCircularItem pPointer;
CirKillFunc killer;
}Circular;
/*=========================================================================
Functions for Birth and Death
*/
pCircular createCircular(int iSize, CirKillFunc kf)
{
pCircular pNew = NULL;
pCircularItem pItem = NULL, pFirst = NULL;
int i;
assert(iSize > 0);
/* create data structure */
pNew = (pCircular)malloc(sizeof(Circular));
if(!pNew)
return NULL;
memset(pNew,0,sizeof(Circular));
/* create all the members of the circular buffer */
pItem = (pCircularItem)malloc(sizeof(CircularItem));
if(!pItem)
return NULL;
memset(pItem,0,sizeof(CircularItem));
pNew->pPointer = pItem;
pFirst = pItem;
for(i = 1; i < iSize; i++)
{
pItem = (pCircularItem)malloc(sizeof(CircularItem));
if(!pItem)
return NULL;
memset(pItem,0,sizeof(CircularItem));
pItem->previous = pNew->pPointer;
pNew->pPointer->next = pItem;
pNew->pPointer = pItem;
}
pItem->next = pFirst;
pFirst->previous = pItem;
pNew->killer = kf;
return pNew;
}
/*---------------------------------------------------------------------*/
void deleteCircular(pCircular self)
{
pCircularItem pNext = NULL, pCurrent = NULL;
assert(self);
self->pPointer->previous->next = NULL;
pNext = self->pPointer;
while(pNext != NULL)
{
pCurrent = pNext;
pNext = pCurrent->next;
if(pCurrent->pData && self->killer)
{
self->killer(pCurrent->pData);
}
free(pCurrent);
}
free(self);
}
/*========================================================================
Data Manipulation functions
*/
void setCircular(pCircular self, void *pData)
{
assert(self);
/* delete if present */
if(self->pPointer->pData && self->killer)
{
self->killer(self->pPointer->pData);
}
self->pPointer->pData = pData;
}
/*----------------------------------------------------------------------*/
void *getCircular(pCircular self)
{
assert(self);
return self->pPointer->pData;
}
/*========================================================================
Pointer movement
*/
void nextCircular(pCircular self)
{
assert(self);
self->pPointer = self->pPointer->next;
}
/*---------------------------------------------------------------------*/
void previousCircular(pCircular self)
{
assert(self);
self->pPointer = self->pPointer->previous;
}

31
circular.h Normal file
View File

@ -0,0 +1,31 @@
/*--------------------------------------------------------------------------
C I R C U L A R
This is the implementation of a general purpose circular buffer facility.
Mark Koennecke, October 1999
--------------------------------------------------------------------------*/
#ifndef CIRCULAR
#define CIRCULAR
typedef struct __CIRCULAR *pCircular;
typedef void (*CirKillFunc)(void *pData);
/* ----------------- birth and death -----------------------------------*/
pCircular createCircular(int iSize,CirKillFunc kf);
/*
iSize is the size of the circular Buffer.
KillFunc is a function which can safely delete the data item held
as content of the circular buffer.
*/
void deleteCircular(pCircular self);
/*-------------- access and modify data item at current position ----------*/
void setCircular(pCircular self, void *pData);
void *getCircular(pCircular self);
/*---------------- pointer movement --------------------------------------*/
void nextCircular(pCircular self);
void previousCircular(pCircular self);
#endif

44
codri.h Normal file
View File

@ -0,0 +1,44 @@
/*-------------------------------------------------------------------------
C o n t r o l l e r D r i v e r
This file contains the description of the data structure for a
general controller driver.
Mark Koennecke, January 1998
--------------------------------------------------------------------------*/
#ifndef CODRIV
#define CODRIV
#define CHFAIL -1
#define CHREDO -2
#define CHOK -3
typedef struct __CODRI *pCodri;
typedef struct __CODRI {
int (*Init)(pCodri self);
int (*Close)(pCodri self);
int (*Delete)(pCodri self);
int (*SetPar)(pCodri self,
char *parname,
float fValue);
int (*SetPar2)(pCodri self,
char *parname,
char *value);
int (*GetPar)(pCodri self,
char *parname,
char *pBuffer,
int iBufLen);
int (*CheckPar)(pCodri self,
char *parname);
int (*GetError)(pCodri self, int *iCode,
char *pError,
int iErrLen);
int (*TryFixIt)(pCodri self, int iCode);
int (*Halt)(pCodri self);
char *pParList;
void *pPrivate;
}Codri;
#endif

229
coll.tcl Normal file
View File

@ -0,0 +1,229 @@
#----------------------------------------------------------------------------
# This file implements the collimator commands for SANS. It requires an
# SPS named sps2 within SICS.
#
# Mark Koennecke, March 1999
#----------------------------------------------------------------------------
proc coll args {
#-------- set case
if { [llength $args] > 0 ] } {
set length [lindex $args 0]
switch $length {
18 {
set command "sps2 push 200 0"
break
}
15 {
set command "sps2 push 200 1"
break
}
11 {
set command "sps2 push 200 2"
break
}
8 {
set command "sps2 push 200 3"
break
}
6 {
set command "sps2 push 200 4"
break
}
4.5 {
set command "sps2 push 200 5"
break
}
3 {
set command "sps2 push 200 6"
break
}
2 {
set command "sps2 push 200 7"
break
}
1.4 {
set command "sps2 push 201 0"
break
}
1 {
set command "sps2 push 201 1"
break
}
default {
append text \
[format "ERROR: collimation length %s invalid\n" $length]
append text "Possible length are: 18,15,11,8,6,4.5,3,2,1.4,1\n"
append text \
"Extraneous . or other characters will yield this error too\n"
append text "SPS programming courtesy Enzo Manfrin\n"
return $text
}
#------- command has been built, execute it!
set ret [catch {$command} msg]
if {$ret != 0} {
error $msg
}
setstatus Driving
#------- wait till finish, check for interrupts on the way
set exe 1
while {$exe} {
set ret [catch {sps2 colli} msg]
if {$ret != 0 } {
setstatus Eager
error $msg
}
set l [split $msg =]
set cval [lindex $l 1]
if { [expr $cval - $length] < 0.2 } {
set exe 0
}
set rupt [getint]
if {[string compare $rupt continue] != 0 } {
setstatus Eager
error "ERROR: driving collimator interrupted"
}
}
setstatus Eager
return OK
} else {
#-------- get case
set ret [catch {sps2 colli} msg]
if {$ret != 0} {
error $msg
}
return $msg
}
}
#--------------------------------------------------------------------------
# Another procedure for handling the attenuator.
#
# Mark Koennecke, March 1999
#--------------------------------------------------------------------------
proc findatt { } {
#----------- find the current attenuator
set ret [catch {sps2 stat2 9 5} msg]
if { $ret != 0 } {
error $msg
}
set l [split $msg =]
if { [lindex $l 1] == 1} {
return 0
}
set ret [catch {sps2 stat2 9 6} msg]
if { $ret != 0 } {
error $msg
}
set l [split $msg =]
if { [lindex $l 1] == 1} {
return 1
}
set ret [catch {sps2 stat2 9 7} msg]
if { $ret != 0 } {
error $msg
}
set l [split $msg =]
if { [lindex $l 1] == 1} {
return 2
}
set ret [catch {sps2 stat2 10 0} msg]
if { $ret != 0 } {
error $msg
}
set l [split $msg =]
if { [lindex $l 1] == 1} {
return 3
}
set ret [catch {sps2 stat2 10 1} msg]
if { $ret != 0 } {
error $msg
}
set l [split $msg =]
if { [lindex $l 1] == 1} {
return 4
}
set ret [catch {sps2 stat2 10 2} msg]
if { $ret != 0 } {
error $msg
}
set l [split $msg =]
if { [lindex $l 1] == 1} {
return 5
}
}
#--------------------------------------------------------------------------
proc att args {
if [ llength $args] > 0} {
#------- set case
set aat [lindex $args 0]
switch $aat {
0 {
set command "sps2 push 210 7"
break
}
1 {
set command "sps2 push 220 0"
break
}
2 {
set command "sps2 push 220 1"
break
}
3 {
set command "sps2 push 230 0"
break
}
4 {
set command "sps2 push 230 1"
break
}
5 {
set command "sps2 push 230 2"
break
}
default {
error [format "ERROR: attenuator %s unknown" $aat]
}
}
#-----send command
set ret [catch {$command} msg]
if {$ret != 0} {
error $msg
}
#------ wait till done
setstatus Driving
set exe 1
while {$exe} {
set ret [catch {findatt} msg]
if {$ret != 0 } {
setstatus Eager
error $msg
}
if { [expr $msg - $aat] < 0.2 } {
set exe 0
}
set rupt [getint]
if {[string compare $rupt continue] != 0 } {
setstatus Eager
error "ERROR: driving attenuator interrupted"
}
}
setstatus Eager
return OK
} else {
#----------- get case
set ret [catch {findatt} msg]
if {$ret != 0 } {
error $msg
} else {
return [format "att = %s" $msg]
}
}
}

79
collidertest.tcl Normal file
View File

@ -0,0 +1,79 @@
#--------------------------------------------------------------------------
# test and example script for the anticollider
#
# Mark Koennecke, August 2002
#------------------------------------------------------------------------
proc testlimits tg {
upvar $tg targets
if { abs( $targets(om) - $targets(stt)) < 30 } {
error "!!!!! two theta - omega CRASH!!!!!!!"
}
if {$targets(chi) > 190.} {
error "chi upperlimit crashed"
}
if { $targets(om) > -90 && $targets(om) <= -81.5 && $targets(chi) < 152} {
error "!!!!!! chi - omega CRASH aborted !!!!!"
}
if { $targets(om) > -81.5 && $targets(om) <= -55 && $targets(chi) < 137} {
error "!!!!!! chi - omega CRASH aborted !!!!!"
}
if { $targets(om) > -55 && $targets(om) <= -52 && $targets(chi) < 132} {
error "!!!!!! chi - omega CRASH aborted !!!!!"
}
if { $targets(om) > -52 && $targets(om) <= -30 && $targets(chi) < 75} {
error "!!!!!! chi - omega CRASH aborted !!!!!"
}
return
}
#-------------------------------------------------------------------------
proc chiFirst? tg {
upvar $tg targets
set om [SplitReply [om]]
set chi [SplitReply [chi]]
if {$chi < $targets(chi) } {
return 1
} else {
return 0
}
}
#---------------------------------------------------------------------------
proc collidertest args {
#----------- read command line targets
set entries [expr [llength $args] / 2]
for {set i 0} {$i < $entries} {incr i} {
set ind [expr $i * 2]
set targets([lindex $args $ind]) [lindex $args [expr $ind +1]]
}
#--------- check if all motors are there. If not get targets from
# current position
if { [info exists targets(om)] == 0} {
set targets(om) [SplitReply [om]]
}
if { [info exists targets(stt)] == 0} {
set targets(stt) [SplitReply [stt]]
}
if { [info exists targets(chi)] == 0} {
set targets(chi) [SplitReply [chi]]
}
if { [info exists targets(phi)] == 0} {
set targets(phi) [SplitReply [phi]]
}
#---------- proceed to real collision detection hydraulics
# first: test complex limits
set ret [catch {testlimits targets} msg]
if {$ret != 0} {
clientput [format "ERROR %s" $msg]
error $msg
}
anticollision add 1 stt $targets(stt)
if { [chiFirst? targets] == 1} {
anticollision add 2 chi $targets(chi)
anticollision add 3 om $targets(om)
} else {
anticollision add 2 om $targets(om)
anticollision add 3 chi $targets(chi)
}
anticollision add 3 phi $targets(phi)
}

54
comentry.h Normal file
View File

@ -0,0 +1,54 @@
/*---------------------------------------------------------------------------
C O M E N T R Y
some helper stuff for implementing MultiMotors. Functions in mumo.c
Mark Koennecke, February 1997
---------------------------------------------------------------------------*/
#ifndef COMENTRY
#define COMENTRY
#define MAXDEV 10
typedef struct {
void *pData;
char name[80];
pObjectDescriptor pDescriptor;
float fVal;
int iCount;
} DevEntry;
/* -------------------The Entry per registered command --------------------*/
typedef struct __ComEntry {
char name[10];
char *pCommand;
int iDevice;
DevEntry pDevice[MAXDEV];
struct __ComEntry *pNext;
struct __ComEntry *pPrevious;
}ComEntry, *pComEntry;
typedef struct __NAMPOS {
char *name; /* the name */
pComEntry pCom; /* the positions */
char *text; /* explanatory text */
struct __NAMPOS *pNext;
struct __NAMPOS *pPrevious;
} NamPos, *pNamPos;
typedef struct __NAMMAP {
char *alias;
char *motname;
pMotor pMot;
} NamMap, *pNamMap;
int CheckComEntryBounds(pComEntry self, SConnection *pCon);
int AddExeEntry(pExeList self, pComEntry pNew, SConnection *pCon);
pComEntry CreateComEntry(void);
pComEntry CopyComEntry(pComEntry pOld);
int AddDevEntry(pComEntry pCom, char *name, void *pData, pObjectDescriptor pDes,
float fVal);
pNamPos LinkNamPos(pNamPos pHead, pNamPos pNew);
pNamPos UnlinkNamPos(pNamPos pHead, pNamPos pOld);
#endif

476
commandlog.c Normal file
View File

@ -0,0 +1,476 @@
/*--------------------------------------------------------------------------
C O M M A N D L O G
A much requested facility for writing only user and manager level commands
in a transcript file. This is it.
Mark Koennecke, June 1998
Extended to support Heinz Heers autolog-file
Mark Koennecke, April-May 1999
Added a tail facility
Mark Koennecke, October 1999
--------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <time.h>
#include <tcl.h>
#include "sics.h"
#include "ifile.h"
#include "sicsvar.h"
#include "scaldate.h"
#include "network.h"
#include "circular.h"
/* in conman.c */
int TelnetWrite(mkChannel *pSock, char *pText);
/*-------------------- the command log file pointer ---------------------*/
static FILE *fd = NULL;
static FILE *fauto = NULL;
static char pFile[256];
/*-------------------- the tail buffer ---------------------------------*/
static pCircular pTail = NULL;
#define MAXTAIL 1000
/*----------------------------------------------------------------------*/
void WriteToCommandLog(char *prompt,char *text)
{
int iNL = 0, iPos;
char *pPtr = NULL, *pCopy = NULL, *pText = NULL;
char myBuffer[1024];
/*
we change the text, so we need to make a local copy. A copy
is dynamically allocated only if it does not fit into
myBuffer.
*/
if(strlen(text) > 1023){
pCopy = (char *)malloc((strlen(text)+2)*sizeof(char));
if(pCopy == NULL){
return;
}
memset(pCopy,0,(strlen(text)+2)*sizeof(char));
strcpy(pCopy,text);
pText = pCopy;
} else {
strcpy(myBuffer,text);
pText = myBuffer;
}
/* figure out if we have to do a newline with pText as well */
pPtr = strrchr(pText,'\n');
if(pPtr != NULL)
{
iPos = pPtr - pText;
if(iPos >= (strlen(pText) - 2) )
{
iNL = 1;
}
}
/* supress status messages */
if(strstr(pText,"status =") != NULL)
{
if(pCopy != NULL){
free(pCopy);
}
return;
}
/* suppress TRANSACTIONFINISHED as well in order to make the WWW
commandlog work
*/
if(strstr(pText,"TRANSACTIONFINISHED") != NULL)
{
if(pCopy != NULL){
free(pCopy);
}
return;
}
/* create tail buffer as needed */
if(!pTail)
{
pTail = createCircular(MAXTAIL,free);
}
/* user file */
if(fd != NULL)
{
if(iNL)
{
fprintf(fd,"%s %s",prompt, pText);
}
else
{
fprintf(fd,"%s %s\n",prompt, pText);
}
}
/* automatic file */
if(fauto != NULL)
{
if(iNL)
{
fprintf(fauto,"%s %s",prompt, pText);
}
else
{
fprintf(fauto,"%s %s\n",prompt, pText);
}
}
/* tail buffer */
if(pTail != NULL)
{
if(iNL)
{
pPtr = strrchr(pText,'\n');
*pPtr = ' ';
}
setCircular(pTail,strdup(pText));
nextCircular(pTail);
}
if(pCopy != NULL){
free(pCopy);
}
}
/*------------------------------------------------------------------------*/
static void PrintTail(int iNum, SConnection *pCon)
{
char *pPtr = NULL;
int i;
if(pTail == NULL)
{
SCWrite(pCon,"Nothing to print",eError);
return;
}
/* step back */
for(i = 0; i < iNum; i++)
{
previousCircular(pTail);
}
/* now step ahead and print. I have to use a trick here: I do not
want the tail stuff to show up in log files. Thus I write it
directly to the connection socket.
*/
for(i = 0; i < iNum; i++)
{
pPtr = (char *)getCircular(pTail);
if(pCon->pSock)
{
TelnetWrite(pCon->pSock, pPtr);
}
nextCircular(pTail);
}
}
/*------------------------------------------------------------------------*/
void CLFormatTime(char *pBuffer, int iBufLen)
{
time_t iDate;
struct tm *psTime;
/* make time string */
iDate = time(NULL);
psTime = localtime(&iDate);
memset(pBuffer,0,iBufLen);
strftime(pBuffer,iBufLen,"%Y-%m-%d@%H-%M-%S",psTime);
}
/*----------------------------------------------------------------------
Build an automatically generated log file name and open it.
*/
static void AutoLog(void)
{
char pBueffel[1024];
char pTime[80];
pSicsVariable pInst = NULL;
char *pPtr = NULL;
SConnection *pIntern = NULL;
if(fauto)
{
fclose(fauto);
fauto = NULL;
}
/* find path */
pPtr = IFindOption(pSICSOptions,"LogFileDir");
if(!pPtr)
{
pPtr = strdup("~/log");
printf("WARNING: Required SICS option LogFileDir not found");
}
/* get time */
CLFormatTime(pTime,79);
/* build file name */
sprintf(pBueffel,"%s/auto%s.log",pPtr,pTime);
/* open file */
fauto = fopen(pBueffel,"w");
if(!fauto)
{
ServerWriteGlobal("ERROR: failed to open autolog file",eError);
}
/* write the instrument name to it for identification */
pInst = FindVariable(pServ->pSics,"instrument");
if(pInst)
{
sprintf(pBueffel,"Logfile started at instument %s at %s",
pInst->text,pTime);
WriteToCommandLog("SYS>> ", pBueffel);
}
/* if a file to execute is configured, execute it */
pPtr = NULL;
pPtr = IFindOption(pSICSOptions,"logstartfile");
if(pPtr != NULL)
{
pIntern = SCCreateDummyConnection(pServ->pSics);
if(!pIntern)
{
return;
}
SCnoSock(pIntern);
SCSetRights(pIntern,usUser);
sprintf(pBueffel,"fileeval %s",pPtr);
InterpExecute(pServ->pSics,pIntern,pBueffel);
SCDeleteConnection(pIntern);
}
}
/*----------------------------------------------------------------------
AutoTask puts a time stamp into the auto log file any hour and
creates a new log file any 24 hours
*/
static time_t tLogfile = 0;
static time_t tStamp = 0;
static int iEnd = 1;
static int iAutoActive = 0;
static int iIntervall = 60;
static int AutoTask(void *pData)
{
time_t tNow;
char pTime[80];
struct tm *sTime;
long julian;
unsigned yr, mo, dd;
tNow = time(NULL);
if(tNow > tLogfile)
{
AutoLog();
sTime = localtime(&tNow);
/* find next day, do so by converting to julian Date, add one
and calculate back. The (stolen) julian calculations will
take care of all the leaps and month and year etc.
*/
julian = ymd_to_scalar(sTime->tm_year+1900, sTime->tm_mon+1,
sTime->tm_mday);
julian++;
scalar_to_ymd(julian, &yr, &mo, &dd);
sTime->tm_sec = 0;
sTime->tm_min = 1;
sTime->tm_hour = 0;
sTime->tm_mday = dd;
sTime->tm_mon = mo - 1;
sTime->tm_year = yr - 1900;
tLogfile = mktime(sTime);
if(tLogfile < 0)
tLogfile = tNow + 60*60*24;
}
if(tNow > tStamp)
{
CLFormatTime(pTime,79);
WriteToCommandLog("TIMESTAMP>> ",pTime);
sTime = localtime(&tNow);
sTime->tm_sec = 0;
sTime->tm_min += iIntervall;
if(sTime->tm_min >= 60)
{
sTime->tm_min = 0;
sTime->tm_hour++;
}
if(sTime->tm_hour >= 24)
sTime->tm_hour = 0;
tStamp = mktime(sTime);
if((tStamp < 0) || ( (tStamp-tNow) < 100) )
{
tStamp = tNow + iIntervall*60;
}
if(fauto)
fflush(fauto);
}
return iEnd;
}
/*----------- a command to configure the log --------------------------*/
int CommandLog(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
char *pPtr = NULL;
char pBueffel[1024];
int iVal, iRet;
if(argc == 1)
{
if(fd)
{
sprintf(pBueffel,"Command log ACTIVE at %s",pFile);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
else
{
SCWrite(pCon,"Command logging DISABLED",eValue);
return 1;
}
}
/* handle tail */
strtolower(argv[1]);
if(strcmp(argv[1],"tail") == 0)
{
/* check for optional number of lines argument */
iVal = 20;
if(argc >= 3)
{
iRet = Tcl_GetInt(pSics->pTcl,argv[2],&iVal);
if(iRet != TCL_OK)
iVal = 20;
}
PrintTail(iVal,pCon);
return 1;
}
/* check rights */
if(!SCMatchRights(pCon,usMugger))
{
SCWrite(pCon,"ERROR: only managers may configure the logfile",
eError);
SCWrite(pCon,"ERROR: Request refused",eError);
return 0;
}
/* check no of args */
if(argc < 2)
{
SCWrite(pCon,
"ERROR: Insufficient number or arguments to commandlog",
eError);
return 0;
}
if(strcmp(argv[1],"new") == 0) /* new command */
{
if(argc < 3)
{
SCWrite(pCon,
"ERROR: Insufficient number or arguments to commandlog new",
eError);
return 0;
}
if(fd)
{
fclose(fd);
fd = NULL;
}
/* make the filename */
pPtr = IFindOption(pSICSOptions,"LogFileDir");
if(!pPtr)
{
SCWrite(pCon,"WARNING: no log file directory specified",eWarning);
sprintf(pBueffel,"%s",argv[2]);
}
else
{
sprintf(pBueffel,"%s/%s",pPtr,argv[2]);
}
fd = fopen(pBueffel,"w");
if(!fd)
{
sprintf(pBueffel,"ERROR: cannot open %s/%s for writing",pPtr,
argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
strcpy(pFile,argv[2]);
SCSendOK(pCon);
return 1;
}
else if(strcmp(argv[1],"auto") == 0)
{
if(iAutoActive)
{
SCWrite(pCon,"ERROR: autologging is already active",eError);
return 0;
}
TaskRegister(pServ->pTasker,
AutoTask,
NULL,
NULL,
NULL,
1);
SCSendOK(pCon);
iAutoActive = 1;
return 1;
}
else if(strcmp(argv[1],"intervall") == 0)
{
if(argc > 2)
{
iRet = Tcl_GetInt(pSics->pTcl,argv[2],&iVal);
if(iRet != TCL_OK)
{
SCWrite(pCon,"ERROR: failed to convert new intervall to number",
eError);
return 0;
}
iIntervall = iVal;
SCSendOK(pCon);
return 1;
}
else
{
sprintf(pBueffel,"autolog.intervall = %d", iIntervall);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
}
else if(strcmp(argv[1],"close") == 0) /* close command */
{
fclose(fd);
fd = NULL;
SCSendOK(pCon);
return 1;
}
sprintf(pBueffel,"ERROR: subcommand %s to commandlog unknown",
argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/*-------------------------------------------------------------------------*/
void CommandLogClose(void *pData)
{
if(fd)
{
fclose(fd);
}
if(fauto)
fclose(fauto);
if(pData)
KillDummy(pData);
if(pTail)
deleteCircular(pTail);
}

19
commandlog.h Normal file
View File

@ -0,0 +1,19 @@
/*--------------------------------------------------------------------------
C O M M A N D L O G
A much requested facility for writing only user an manager level commands
in a transcript file. This is it.
Mark Koennecke, June 1998
--------------------------------------------------------------------------*/
#ifndef COMMANDLOG
#define COMMANDLOG
void WriteToCommandLog(char *prompt,char *pText);
int CommandLog(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
void CommandLogClose(void *pData);
#endif

26
configfu.h Normal file
View File

@ -0,0 +1,26 @@
/*--------------------------------------------------------------------------
` This is a common header for rarely used configuration
functions. Implementations are distributed across several
files. Therefor they are mentioned in a comment.
Mark Koennecke, December 1996
copyrights: see implementation files
--------------------------------------------------------------------------*/
#ifndef SICSCONFIG
#define SICSCONFIG
int AddHalt(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/* configuration command: enters argv objects into Halt List of Interrupt.
This is the means how the server knows which hardware to halt in an
case of emergency. Implemented in intserv.c
*/
int ListObjects(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/*
lists all avialable objects. Realised in Scinter.c
*/
#endif

1813
conman.c Normal file

File diff suppressed because it is too large Load Diff

130
conman.h Normal file
View File

@ -0,0 +1,130 @@
/*--------------------------------------------------------------------------
C O N N E C T I O N O B J E C T
This file defines the connection object data structure and the interface to
this data structure. This is one of the most important SICS components.
Substantially revised from a prior version.
Mark Koennecke, September 1997
copyright: see copyright.h
----------------------------------------------------------------------------*/
#ifndef SICSCONNECT
#define SICSCONNECT
#include <stdio.h>
#include "costa.h"
#include "SCinter.h"
#include "network.h"
#include "obdes.h"
#define MAXLOGFILES 10
typedef int (*writeFunc)(struct __SConnection *pCon,
char *pMessage, int iCode);
typedef struct __SConnection {
/* object basics */
pObjectDescriptor pDes;
char *pName;
long lMagic;
/* I/O control */
mkChannel *pSock;
FILE *pFiles[MAXLOGFILES];
int iMacro;
int iTelnet;
int iOutput;
int iFiles;
writeFunc write;
mkChannel *pDataSock;
char *pDataComp;
int iDataPort;
/* execution context */
int eInterrupt;
int iUserRights;
int inUse;
int iGrab;
SicsInterp *pSics;
/* flag for parameter change */
int parameterChange;
/* a FIFO */
pCosta pStack;
/* callback registry */
int iList;
/* Tasking Stuff */
int iEnd;
/* for keeping track of the login
process on a non telnet connection.
Should only be used in SCTaskFunction
*/
int iLogin;
time_t conStart;
}SConnection;
#include "nserver.h"
/*------------------------------ live & death ----------------------------*/
SConnection *SCreateConnection(SicsInterp *pSics, mkChannel *pSock,
int iUserRights);
SConnection *SCCreateDummyConnection(SicsInterp *pSics);
void SCDeleteConnection(void *pVictim);
/*------------------------------- tasking --------------------------------*/
int SCTaskFunction(void *pCon);
void SCSignalFunction(void *pCon, int iSignal, void *pSigData);
/* ***************************** I/O ************************************** */
int SCAddLogFile(SConnection *self, char *name);
int SCDelLogFile(SConnection *pCon, int iFile);
void SCSetOutputClass(SConnection *self, int iClass);
int SCWrite(SConnection *self, char *pBuffer, int iOut);
int SCRead(SConnection *self, char *pBuffer, int iBufLen);
int SCPrompt(SConnection *pCon, char *pPrompt, char *pResult, int iLen);
int SCSendOK(SConnection *self);
int SCnoSock(SConnection *pCon);
int SCWriteUUencoded(SConnection *pCon, char *pName, void *iData, int iLen);
int SCWriteZipped(SConnection *pCon, char *pName, void *pData, int iDataLen);
writeFunc SCGetWriteFunc(SConnection *pCon);
void SCSetWriteFunc(SConnection *pCon, writeFunc x);
int SCOnlySockWrite(SConnection *self, char *buffer, int iOut);
int SCNotWrite(SConnection *self, char *buffer, int iOut);
/************************* CallBack *********************************** */
int SCRegister(SConnection *pCon, SicsInterp *pSics,
void *pInter, long lID);
int SCUnregister(SConnection *pCon, void *pInter);
/******************************* Interrupt *********************************/
void SCSetInterrupt(SConnection *self, int eCode);
int SCGetInterrupt(SConnection *self);
/****************************** Macro ***************************************/
int SCinMacro(SConnection *pCon);
int SCsetMacro(SConnection *pCon, int iMode);
/************************** parameters changed ? **************************/
void SCparChange(SConnection *pCon);
/* *************************** Info *************************************** */
int SCGetRights(SConnection *self);
int SCSetRights(SConnection *pCon, int iNew);
int SCMatchRights(SConnection *pCon, int iCode);
int SCGetOutClass(SConnection *self);
int SCGetGrab(SConnection *pCon);
/********************* simulation mode ************************************/
void SCSetSimMode(SConnection *pCon, int value);
int SCinSimMode(SConnection *pCon);
/* **************************** Invocation ******************************** */
int SCInvoke(SConnection *self,SicsInterp *pInter,char *pCommand);
/*************************** User Command **********************************/
int ConfigCon(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int ConSicsAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif

31
copyright.h Normal file
View File

@ -0,0 +1,31 @@
/*----------------------------------------------------------------------------
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
Author: Mark Koennecke
Laboratory for Neutron Scattering
Paul Scherrer Institut
CH-5232 Villigen-PSI
Switzerland
Mark.Koennecke@psi.ch
-----------------------------------------------------------------------------*/

198
costa.c Normal file
View File

@ -0,0 +1,198 @@
/*----------------------------------------------------------------------------
C O S T A
Implementation of a command stack for use with connection objects in
SICS
Mark Koennecke, Septemeber 1997
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>
#include "fortify.h"
#include "lld.h"
#include "costa.h"
#include "costa.i"
/*-------------------------------------------------------------------------*/
pCosta CreateCommandStack(void)
{
pCosta pNew = NULL;
pNew = (pCosta)malloc(sizeof(Costa));
if(!pNew)
{
return NULL;
}
memset(pNew,0,sizeof(Costa));
pNew->iList = LLDcreate(sizeof(char *));
if(pNew->iList < 0)
{
free(pNew);
return NULL;
}
pNew->iCount = 0;
pNew->iMaxSize = INT_MAX;
return pNew;
}
/*-------------------------------------------------------------------------*/
void DeleteCommandStack(pCosta self)
{
int iRet;
char *pPtr;
assert(self);
iRet = LLDnodePtr2First(self->iList);
while(iRet != 0)
{
pPtr = NULL;
LLDnodeDataTo(self->iList,&pPtr);
if(pPtr)
{
free(pPtr);
}
iRet = LLDnodePtr2Next(self->iList);
}
LLDdelete(self->iList);
free(self);
}
/*--------------------------------------------------------------------------*/
int SetCommandStackMaxSize(pCosta self, int iNew)
{
assert(self);
if(iNew > 0)
{
self->iMaxSize = iNew;
return 1;
}
else
{
return 0;
}
}
/*--------------------------------------------------------------------------*/
int CostaTop(pCosta self, char *pCommand)
{
char *pPtr = NULL;
int iRet, iRes = 1;
assert(self);
/* check for lock */
if(self->iLock)
{
return 0;
}
/* check Size */
if(self->iCount >= self->iMaxSize)
{
return 0;
}
/* do not want 0 commands */
if(strlen(pCommand) < 1)
{
return 1;
}
pPtr = strdup(pCommand);
iRet = LLDnodeAppendFrom(self->iList,&pPtr);
if(iRet < 0)
{
iRes = 0;
}
self->iCount++;
return iRes;
}
/*--------------------------------------------------------------------------*/
int CostaBottom(pCosta self, char *pCommand)
{
char *pPtr = NULL;
int iRet, iRes = 1;
assert(self);
/* check for lock */
if(self->iLock)
{
return 0;
}
/* do not want 0 commands */
if(strlen(pCommand) < 1)
{
return 1;
}
pPtr = strdup(pCommand);
iRet = LLDnodePrependFrom(self->iList,&pPtr);
if(iRet < 0)
{
iRes = 0;
}
self->iCount++;
return iRes;
}
/*--------------------------------------------------------------------------*/
int CostaPop(pCosta self, char **pBuf)
{
char *pPtr = NULL;
int iRet;
assert(self);
iRet = LLDnodePtr2First(self->iList);
if(iRet != 0)
{
LLDnodeDataTo(self->iList,&pPtr);
*pBuf = pPtr;
LLDnodeDelete(self->iList);
self->iCount--;
return 1;
}
*pBuf = NULL;
return 0;
}
/*--------------------------------------------------------------------------*/
void CostaLock(pCosta self)
{
self->iLock = 1;
}
/*--------------------------------------------------------------------------*/
void CostaUnlock(pCosta self)
{
self->iLock = 0;
}

29
costa.h Normal file
View File

@ -0,0 +1,29 @@
/*-------------------------------------------------------------------------
C O S T A
A command stack implementation for SICS. To be used by each connection.
Mark Koennecke, September 1997
copyright: see implementation file.
----------------------------------------------------------------------------*/
#ifndef SICSCOSTA
#define SICSCOSTA
typedef struct __costa *pCosta;
/*----------------------------- live & death ----------------------------*/
pCosta CreateCommandStack(void);
void DeleteCommandStack(pCosta self);
int SetCommandStackMaxSize(pCosta self, int iNewSize);
/*----------------------------------------------------------------------*/
int CostaTop(pCosta self, char *pCommand);
int CostaBottom(pCosta self, char *pCommand);
int CostaPop(pCosta self,char **pPtr);
/*----------------------------------------------------------------------*/
void CostaLock(pCosta self);
void CostaUnlock(pCosta self);
#endif

15
costa.i Normal file
View File

@ -0,0 +1,15 @@
/*---------------------------------------------------------------------------
C O S T A
Internal data structures for the command stack.
--------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
typedef struct __costa {
int iLock;
int iList;
int iMaxSize;
int iCount;
} Costa;

108
costa.tex Normal file
View File

@ -0,0 +1,108 @@
\subsection{The Command Stack}
This is a helper class to the connection class.
Each connection to a client has a command stack associated with it. The
command stack is a stack of command strings as generated by the SICS
clients. Commands are added to the top of the command queue by the network
reader. Each time the task associated with a connection runs one command
is popped from the command stack and executed. During execution the command
stack must be locked in order to prevent commands being accepted by tasks
busy waiting for some other process to finish.
Correspondingly, the interface to the command stack looks like this:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
$\langle$costaint {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ typedef struct __costa *pCosta;@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*----------------------------- live & death ----------------------------*/@\\
\mbox{}\verb@ pCosta CreateCommandStack(void);@\\
\mbox{}\verb@ void DeleteCommandStack(pCosta self);@\\
\mbox{}\verb@ int SetCommandStackMaxSize(pCosta self, int iNewSize);@\\
\mbox{}\verb@/*----------------------------------------------------------------------*/@\\
\mbox{}\verb@ int CostaTop(pCosta self, char *pCommand);@\\
\mbox{}\verb@ int CostaBottom(pCosta self, char *pCommand);@\\
\mbox{}\verb@ int CostaPop(pCosta self,char **pPtr);@\\
\mbox{}\verb@/*----------------------------------------------------------------------*/@\\
\mbox{}\verb@ void CostaLock(pCosta self);@\\
\mbox{}\verb@ void CostaUnlock(pCosta self);@\\
\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}
Internally, two data structure need to be defined, the first for the
list implementing the command stack, the second for the command stack
itself.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap2}
$\langle$costadat {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ typedef struct __costa {@\\
\mbox{}\verb@ int iLock;@\\
\mbox{}\verb@ int iList;@\\
\mbox{}\verb@ int iMaxSize;@\\
\mbox{}\verb@ int iCount;@\\
\mbox{}\verb@ } Costa;@\\
\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{scrap3}
\verb@"costa.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
\mbox{}\verb@ C O S T A@\\
\mbox{}\verb@@\\
\mbox{}\verb@ A command stack implementation for SICS. To be used by each connection.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, September 1997@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see implementation file.@\\
\mbox{}\verb@@\\
\mbox{}\verb@----------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSCOSTA@\\
\mbox{}\verb@#define SICSCOSTA@\\
\mbox{}\verb@@$\langle$costaint {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
\verb@"costa.i"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*---------------------------------------------------------------------------@\\
\mbox{}\verb@ C O S T A@\\
\mbox{}\verb@ Internal data structures for the command stack.@\\
\mbox{}\verb@--------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$costadat {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

68
costa.w Normal file
View File

@ -0,0 +1,68 @@
\subsection{The Command Stack}
This is a helper class to the connection class.
Each connection to a client has a command stack associated with it. The
command stack is a stack of command strings as generated by the SICS
clients. Commands are added to the top of the command queue by the network
reader. Each time the task associated with a connection runs one command
is popped from the command stack and executed. During execution the command
stack must be locked in order to prevent commands being accepted by tasks
busy waiting for some other process to finish.
Correspondingly, the interface to the command stack looks like this:
@d costaint @{
typedef struct __costa *pCosta;
/*----------------------------- live & death ----------------------------*/
pCosta CreateCommandStack(void);
void DeleteCommandStack(pCosta self);
int SetCommandStackMaxSize(pCosta self, int iNewSize);
/*----------------------------------------------------------------------*/
int CostaTop(pCosta self, char *pCommand);
int CostaBottom(pCosta self, char *pCommand);
int CostaPop(pCosta self,char **pPtr);
/*----------------------------------------------------------------------*/
void CostaLock(pCosta self);
void CostaUnlock(pCosta self);
@}
Internally, two data structure need to be defined, the first for the
list implementing the command stack, the second for the command stack
itself.
@d costadat @{
/*------------------------------------------------------------------------*/
typedef struct __costa {
int iLock;
int iList;
int iMaxSize;
int iCount;
} Costa;
@}
@o costa.h @{
/*-------------------------------------------------------------------------
C O S T A
A command stack implementation for SICS. To be used by each connection.
Mark Koennecke, September 1997
copyright: see implementation file.
----------------------------------------------------------------------------*/
#ifndef SICSCOSTA
#define SICSCOSTA
@<costaint@>
#endif
@}
@o costa.i @{
/*---------------------------------------------------------------------------
C O S T A
Internal data structures for the command stack.
--------------------------------------------------------------------------*/
@<costadat@>
@}

37
cotop.tcl Normal file
View File

@ -0,0 +1,37 @@
#--------------------------------------------------------------------------
# A MAD lookalike co command for TOPSI
# All arguments are optional. The current values will be used if not
# specified
# Dr. Mark Koennecke, November 1999
#--------------------------------------------------------------------------
proc SplitReply { text } {
set l [split $text =]
return [lindex $l 1]
}
#--------------------------------------------------------------------------
proc co { {mode NULL } { preset NULL } } {
starttime [sicstime]
#----- deal with mode
set mode2 [string toupper $mode]
set mode3 [string trim $mode2]
set mc [string index $mode2 0]
if { [string compare $mc T] == 0 } {
counter setMode Timer
} elseif { [string compare $mc M] == 0 } {
counter setMode Monitor
}
#------ deal with preset
if { [string compare $preset NULL] != 0 } {
set pre $preset
} else {
set pre [SplitReply [counter getpreset]]
}
#------ count
set ret [catch {counter count $pre} msg]
if { $ret != 0 } {
error [format "Counting ended with error: %s" $msg]
} else {
set cts [SplitReply [counter getcounts]]
}
return $cts
}

752
countdriv.c Normal file
View File

@ -0,0 +1,752 @@
/*------------------------------------------------------------------------
G E N C O U N T
Some general stuff for handling a CounterDriver.
Mark Koennecke, January 1997
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include "fortify.h"
#include <string.h>
#include "sics.h"
#include "countdriv.h"
#include "hardsup/sinq_prototypes.h"
#include "hardsup/el737_def.h"
#include "hardsup/el737fix.h"
/*-------------------------------------------------------------------------*/
pCounterDriver CreateCounterDriver(char *name, char *type)
{
pCounterDriver pRes = NULL;
pRes = (pCounterDriver)malloc(sizeof(CounterDriver));
if(!pRes)
{
return NULL;
}
memset(pRes,0,sizeof(CounterDriver));
pRes->name = strdup(name);
pRes->type = strdup(type);
pRes->eMode = eTimer;
pRes->fPreset = 1000.;
pRes->fTime = 0.;
pRes->iNoOfMonitors = 0;
pRes->iPause = 0;
pRes->Start = NULL;
pRes->GetStatus = NULL;
pRes->ReadValues = NULL;
pRes->GetError = NULL;
pRes->TryAndFixIt = NULL;
pRes->Halt = NULL;
pRes->pData = NULL;
pRes->Pause = NULL;
pRes->Continue = NULL;
return pRes;
}
/*-------------------------------------------------------------------------*/
void DeleteCounterDriver(pCounterDriver self)
{
assert(self);
if(self->name)
{
free(self->name);
}
if(self->type)
{
free(self->type);
}
if(self->pData)
{
free(self->pData);
}
free(self);
}
/*----------------------------- EL737 ------------------------------------*/
typedef struct {
char *host;
int iPort;
int iChannel;
void *pData;
int finishCount;
} EL737st;
/*------------------------------------------------------------------------*/
static int EL737GetStatus(struct __COUNTER *self, float *fControl)
{
int iRet;
int iC1, iC2, iC3,iC4,iRS;
float fTime;
EL737st *pEL737;
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
iRet = EL737_GetStatus(&pEL737->pData,&iC1,&iC2,&iC3,&iC4,&fTime,&iRS);
if(self->eMode == eTimer)
{
*fControl = fTime;
}
else
{
*fControl = iC1;
}
/* store time */
self->fTime = fTime;
if(iRet != 1)
{
return HWFault;
}
self->lCounts[0] = iC2;
self->lCounts[1] = iC1;
self->lCounts[2] = iC3;
self->lCounts[3] = iC4;
/* get extra counters for 8-fold counter boxes */
iRet = EL737_GetStatusExtra(&pEL737->pData,&iC1,&iC2,&iC3,&iC4);
self->lCounts[4] = iC1;
self->lCounts[5] = iC2;
self->lCounts[6] = iC3;
self->lCounts[7] = iC4;
if(iRS == 0)
{
pEL737->finishCount++;
if(pEL737->finishCount >= 2)
{
return HWIdle;
}
else
{
return HWBusy;
}
}
else if((iRS == 1) || (iRS == 2))
{
pEL737->finishCount = 0;
return HWBusy;
}
else if( (iRS == 5) || (iRS == 6))
{
pEL737->finishCount = 0;
return HWNoBeam;
}
else
{
pEL737->finishCount = 0;
return HWPause;
}
}
#ifdef NONINTF
extern float nintf(float f);
#endif
/*-------------------------------------------------------------------------*/
static int EL737Start(struct __COUNTER *self)
{
int iRet, iRS;
EL737st *pEL737;
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
self->fTime = 0.;
if(self->eMode == ePreset)
{
iRet = EL737_StartCnt(&pEL737->pData,(int)nintf(self->fPreset),&iRS);
if(iRet == 1)
{
pEL737->finishCount = 0;
return OKOK;
}
else
{
return HWFault;
}
}
else if(self->eMode == eTimer)
{
iRet = EL737_StartTime(&pEL737->pData,self->fPreset,&iRS);
if(iRet == 1)
{
pEL737->finishCount = 0;
return OKOK;
}
else
{
return HWFault;
}
}
return 0;
}
/*-------------------------------------------------------------------------*/
static int EL737Pause(struct __COUNTER *self)
{
int iRet, iRS;
EL737st *pEL737;
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
iRet = EL737_Pause(&pEL737->pData,&iRS);
if(iRet == 1)
{
return OKOK;
}
else
{
return HWFault;
}
return 0;
}
/*-------------------------------------------------------------------------*/
static int EL737Continue(struct __COUNTER *self)
{
int iRet, iRS;
EL737st *pEL737;
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
iRet = EL737_Continue(&pEL737->pData,&iRS);
if(iRet == 1)
{
return OKOK;
}
else
{
return HWFault;
}
return 0;
}
/*--------------------------------------------------------------------------*/
static int EL737Halt(struct __COUNTER *self)
{
int iRet, iC1, iC2, iC3, iC4,iRS;
float fPreset;
EL737st *pEL737;
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
iRet = EL737_Stop(&pEL737->pData,&iC1, &iC2,&iC3,&iC4,&fPreset,&iRS);
if(iRet == 1)
{
self->lCounts[0] = iC2;
self->lCounts[1] = iC1;
self->lCounts[2] = iC3;
self->lCounts[3] = iC4;
return OKOK;
}
return HWFault;
}
/*--------------------------------------------------------------------------*/
static int EL737ReadValues(struct __COUNTER *self)
{
int iRet;
int iC1, iC2, iC3,iC4,iRS;
float fTime;
EL737st *pEL737;
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
iRet = EL737_GetStatus(&pEL737->pData,&iC1,&iC2,&iC3,&iC4,&fTime,&iRS);
if(iRet != 1)
{
return HWFault;
}
self->fTime = fTime;
self->lCounts[0] = iC2;
self->lCounts[1] = iC1;
self->lCounts[2] = iC3;
self->lCounts[3] = iC4;
/* get extra counters for 8-fold counter boxes */
iRet = EL737_GetStatusExtra(&pEL737->pData,&iC1,&iC2,&iC3,&iC4);
self->lCounts[4] = iC1;
self->lCounts[5] = iC2;
self->lCounts[6] = iC3;
self->lCounts[7] = iC4;
return OKOK;
}
/*---------------------------------------------------------------------------
EL737Error2Text converts between an EL734 error code to text
-----------------------------------------------------------------------------*/
static void EL737Error2Text(char *pBuffer, int iErr)
{
switch(iErr)
{
case EL737__BAD_ADR:
strcpy(pBuffer,"EL737__BAD_ADR");
break;
case EL737__BAD_OVFL:
strcpy(pBuffer,"EL737__BAD_OVFL");
break;
case EL737__BAD_BSY:
strcpy(pBuffer,"EL737__BAD_BSY");
break;
case EL737__BAD_SNTX:
strcpy(pBuffer,"EL737__BAD_SNTX");
break;
case EL737__BAD_CONNECT:
strcpy(pBuffer,"EL737__BAD_CONNECT");
break;
case EL737__BAD_FLUSH:
strcpy(pBuffer,"EL737__BAD_FLUSH");
break;
case EL737__BAD_DEV:
strcpy(pBuffer,"EL734__BAD_DEV");
break;
case EL737__BAD_ID:
strcpy(pBuffer,"EL737__BAD_ID");
break;
case EL737__BAD_ILLG:
strcpy(pBuffer,"EL737__BAD_ILLG");
break;
case EL737__BAD_LOC:
strcpy(pBuffer,"EL737__BAD_LOC");
break;
case EL737__BAD_MALLOC:
strcpy(pBuffer,"EL737__BAD_MALLOC");
break;
case EL737__BAD_NOT_BCD:
strcpy(pBuffer,"EL737__BAD_NOT_BCD");
break;
case EL737__BAD_OFL:
strcpy(pBuffer,"EL737__BAD_OFL");
break;
case EL737__BAD_PAR:
strcpy(pBuffer,"EL737__BAD_PAR");
break;
case EL737__BAD_RECV:
strcpy(pBuffer,"EL737__BAD_RECV");
break;
case EL737__BAD_RECV_NET:
strcpy(pBuffer,"EL737__BAD_RECV_NET");
break;
case EL737__BAD_RECV_PIPE:
strcpy(pBuffer,"EL737__BAD_RECV_PIPE");
break;
case EL737__BAD_RECV_UNKN:
strcpy(pBuffer,"EL737__BAD_RECV_UNKN");
break;
case EL737__BAD_RECVLEN:
strcpy(pBuffer,"EL737__BAD_RECVLEN");
break;
case EL737__BAD_RECV1:
strcpy(pBuffer,"EL737__BAD_RECV1");
break;
case EL737__BAD_RECV1_NET:
strcpy(pBuffer,"EL737__BAD_RECV1_NET");
break;
case EL737__BAD_RECV1_PIPE:
strcpy(pBuffer,"EL737__BAD_RECV1_PIPE");
break;
case EL737__BAD_RNG:
strcpy(pBuffer,"EL737__BAD_RNG");
break;
case EL737__BAD_SEND:
strcpy(pBuffer,"EL737__BAD_SEND");
break;
case EL737__BAD_SEND_PIPE:
strcpy(pBuffer,"EL737__BAD_SEND_PIPE");
break;
case EL737__BAD_SEND_NET:
strcpy(pBuffer,"EL737__BAD_SEND_NET");
break;
case EL737__BAD_SEND_UNKN:
strcpy(pBuffer,"EL737__BAD_SEND_UNKN");
break;
case EL737__BAD_SENDLEN:
strcpy(pBuffer,"EL737__BAD_SENDLEN");
break;
case EL737__BAD_SOCKET:
strcpy(pBuffer,"EL737__BAD_SOCKET");
break;
case EL737__BAD_TMO:
strcpy(pBuffer,"EL737__BAD_TMO");
break;
case EL737__FORCED_CLOSED:
strcpy(pBuffer,"EL737__FORCED_CLOSED");
break;
case EL737__BAD_ASYNSRV:
strcpy(pBuffer,"EL737__BAD_ASYNSRV");
break;
default:
sprintf(pBuffer,"Unknown EL737 error %d", iErr);
break;
}
}
/*--------------------------------------------------------------------------*/
static int EL737GetError(struct __COUNTER *self, int *iCode,
char *error, int iErrLen)
{
char *pErr = NULL;
int iC1, iC2, iC3;
char pBueffel[256];
if(self->iErrorCode == UNKNOWNPAR)
{
strncpy(error,"unknown internal parameter code",iErrLen);
*iCode = self->iErrorCode;
self->iErrorCode = 0;
return 1;
}
else if(self->iErrorCode == BADCOUNTER)
{
strncpy(error,"monitor cannot be selected",iErrLen);
*iCode = self->iErrorCode;
self->iErrorCode = 0;
return 1;
}
EL737_ErrInfo(&pErr,&iC1,&iC2, &iC3);
EL737Error2Text(pBueffel,iC1);
strncpy(error,pBueffel,iErrLen);
*iCode = iC1;
return 1;
}
/*--------------------------------------------------------------------------*/
static int EL737TryAndFixIt(struct __COUNTER *self, int iCode)
{
EL737st *pEL737;
int iRet;
char pCommand[50], pReply[50];
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
switch(iCode)
{
case EL737__BAD_ILLG:
case EL737__BAD_ADR:
case EL737__BAD_PAR:
case EL737__BAD_TMO:
case EL737__BAD_REPLY:
case EL737__BAD_SNTX:
case EL737__BAD_OVFL:
return COREDO;
break;
case EL737__BAD_BSY:
strcpy(pCommand,"S \r");
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
if(iRet < 0)
{
return COTERM;
}
else
{
return COREDO;
}
break;
case EL737__BAD_LOC:
strcpy(pCommand,"rmt 1\r");
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
if(iRet < 0)
{
return COTERM;
}
strcpy(pCommand,"echo 2\r");
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
if(iRet < 0)
{
return COTERM;
}
strcpy(pCommand,"ra\r");
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
if(iRet < 0)
{
return COTERM;
}
return COREDO;
break;
case EL737__BAD_DEV:
case EL737__BAD_ID:
case EL737__BAD_NOT_BCD:
case UNKNOWNPAR:
case BADCOUNTER:
return COTERM;
break;
case EL737__FORCED_CLOSED:
iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort,
pEL737->iChannel);
if(iRet == 1)
{
return COREDO;
}
else
{
return COTERM;
}
break;
case EL737__BAD_OFL:
EL737_Close(&pEL737->pData,0);
iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort,
pEL737->iChannel);
if(iRet == 1)
{
return COREDO;
}
else
{
return COTERM;
}
break;
/* case EL737__BAD_ASYNSRV:
EL737_Close(&pEL737->pData,1);
return COREDO;
*/ default:
/* try to reopen connection */
EL737_Close(&pEL737->pData,1);
iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort,
pEL737->iChannel);
if(iRet == 1)
{
return COREDO;
}
else
{
return COTERM;
}
break;
}
return COTERM;
}
/*-------------------------------------------------------------------------*/
static int EL737Set(struct __COUNTER *self, char *name, int iCter,
float fVal)
{
int iRet;
EL737st *pEL737;
char pCommand[80],pReply[80];
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
if(strcmp(name,"threshold") == 0)
{
sprintf(pCommand,"DL %1.1d %f\r",iCter,fVal);
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79);
if(iRet == 1)
{
if(pCommand[0] == '?')
{
self->iErrorCode = BADCOUNTER;
return HWFault;
}
}
else
{
return HWFault;
}
sprintf(pCommand,"DR %1.1d \r",iCter);
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79);
if(iRet == 1)
{
if(pCommand[0] == '?')
{
self->iErrorCode = BADCOUNTER;
return HWFault;
}
return OKOK;
}
else
{
return HWFault;
}
}
else
{
self->iErrorCode = UNKNOWNPAR;
return HWFault;
}
}
/*-------------------------------------------------------------------------*/
static int EL737Get(struct __COUNTER *self, char *name, int iCter,
float *fVal)
{
int iRet;
EL737st *pEL737;
char pCommand[80],pReply[80];
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
if(strcmp(name,"threshold") == 0)
{
sprintf(pCommand,"DL %1.1d\r",iCter);
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79);
if(iRet == 1)
{
if(pReply[0] == '?')
{
self->iErrorCode = BADCOUNTER;
return HWFault;
}
sscanf(pReply,"%f",fVal);
return OKOK;
}
else
{
return HWFault;
}
}
else
{
self->iErrorCode = UNKNOWNPAR;
return HWFault;
}
}
/*-------------------------------------------------------------------------*/
static int EL737Send(struct __COUNTER *self, char *pText, char *pReply,
int iReplyLen)
{
EL737st *pEL737;
char pBuffer[256];
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
/* ensure a \r at the end of the text */
if(strlen(pText) > 254)
{
strncpy(pReply,"Command to long",iReplyLen);
return 1;
}
strcpy(pBuffer,pText);
if(strchr(pBuffer,(int)'\r') == NULL)
{
strcat(pBuffer,"\r");
}
return EL737_SendCmnd(&pEL737->pData,pBuffer,pReply,iReplyLen);
}
/*--------------------------------------------------------------------------*/
pCounterDriver NewEL737Counter(char *name, char *host, int iPort, int iChannel)
{
pCounterDriver pRes = NULL;
EL737st *pData = NULL;
int iRet;
int iC1, iC2, iC3;
char *pErr;
char pBueffel[132];
pRes = CreateCounterDriver(name, "EL737");
if(!pRes)
{
return NULL;
}
/* open connection to counter */
pData = (EL737st *)malloc(sizeof(EL737st));
if(!pData)
{
DeleteCounterDriver(pRes);
return NULL;
}
pData->host = strdup(host);
pData->iPort = iPort;
pData->iChannel = iChannel;
pData->pData = NULL;
iRet = EL737_Open(&(pData->pData), host,iPort,iChannel);
if(iRet != 1)
{
EL737_ErrInfo(&pErr,&iC1,&iC2, &iC3);
DeleteCounterDriver(pRes);
if(pData->host)
{
free(pData->host);
}
return NULL;
}
pRes->pData = (void *)pData;
/* assign functions */
pRes->GetStatus = EL737GetStatus;
pRes->Start = EL737Start;
pRes->Halt = EL737Halt;
pRes->ReadValues = EL737ReadValues;
pRes->GetError = EL737GetError;
pRes->TryAndFixIt = EL737TryAndFixIt;
pRes->Pause = EL737Pause;
pRes->Continue = EL737Continue;
pRes->Set = EL737Set;
pRes->Get = EL737Get;
pRes->Send = EL737Send;
pRes->iNoOfMonitors = 7;
pRes->fTime = 0.;
return pRes;
}
/*--------------------------------------------------------------------------*/
void KillEL737Counter(pCounterDriver self)
{
EL737st *pEL737 = NULL;
assert(self);
pEL737 = (EL737st *)self->pData;
assert(pEL737);
EL737_Close(&pEL737->pData,0);
if(pEL737->host)
{
free(pEL737->host);
}
DeleteCounterDriver(self);
}

84
countdriv.h Normal file
View File

@ -0,0 +1,84 @@
/*---------------------------------------------------------------------------
C O U N T E R D R I V E R
This is the interface to a Sics-Counter driver. This means a
single counter managing possibly several monitors in one go.
A counter can run for a predefined time or until a predefined
monitor count has been reached.
Mark Koennecke, January 1996
General parameter setting added:
Mark Koennecke, April 1999
copyright: see implementation file.
---------------------------------------------------------------------------*/
#ifndef SICSCOUNTERDRIVER
#define SICSCOUNTERDRIVER
#define COTERM 0
#define COREDO 1
#define MAXCOUNT 9 /* No of monitors + actual counter */
/* Parameter codes for the Set/Get pair of routines */
/*-------- threshold */
#define PARTHRESHOLD 1
/* counter driver additional error codes*/
#define UNKNOWNPAR -5000
#define BADCOUNTER -5001
typedef struct __COUNTER {
/* variables */
char *name;
char *type;
CounterMode eMode;
float fPreset;
float fLastCurrent;
float fTime;
int iNoOfMonitors;
long lCounts[MAXCOUNT];
int iPause;
int iErrorCode;
/* functions */
int (*GetStatus)(struct __COUNTER *self, float *fControl);
int (*Start)(struct __COUNTER *self);
int (*Pause)(struct __COUNTER *self);
int (*Continue)(struct __COUNTER *self);
int (*Halt)(struct __COUNTER *self);
int (*ReadValues)(struct __COUNTER *self);
int (*GetError)(struct __COUNTER *self, int *iCode,
char *error, int iErrLen);
int (*TryAndFixIt)(struct __COUNTER *self, int iCode);
int (*Set)(struct __COUNTER *self,char *name,
int iCter, float fVal);
int (*Get)(struct __COUNTER *self,char *name,
int iCter, float *fVal);
int (*Send)(struct __COUNTER *self, char *pText,
char *pReply, int iReplyLen);
void *pData; /* counter specific data goes here, ONLY for
internal driver use!
*/
} CounterDriver, *pCounterDriver;
/*------------------------------------------------------------------------*/
/* countdriv.c */
pCounterDriver CreateCounterDriver(char *name, char *type);
void DeleteCounterDriver(pCounterDriver self);
/* PSI EL737 Counter */
pCounterDriver NewEL737Counter(char *name, char *host, int iPort,
int iChannel);
void KillEL737Counter(pCounterDriver self);
/* PSI Simulation counter, if you have no hardware */
/* simcter.c */
pCounterDriver NewSIMCounter(char *name, float fVal);
void KillSIMCounter(pCounterDriver self);
#endif

1117
counter.c Normal file

File diff suppressed because it is too large Load Diff

57
counter.h Normal file
View File

@ -0,0 +1,57 @@
/*-------------------------------------------------------------------------
C O U N T E R
The SICS Interface to a single detector and his associated
monitors.
Mark Koennecke, January 1996
copyright: see implementation file.
----------------------------------------------------------------------------*/
#ifndef SICSCOUNTER
#define SICSCOUNTER
#include "countdriv.h"
typedef struct {
pObjectDescriptor pDes;
char *name;
int isUpToDate;
int iExponent;
pICountable pCountInt;
pCounterDriver pDriv;
pICallBack pCall;
unsigned long tStart;
int iCallbackCounter;
} Counter, *pCounter;
/*----------------------------- birth & death -----------------------------*/
pCounter CreateCounter(char *name, pCounterDriver pDriv);
void DeleteCounter(void *self);
int MakeCounter(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/*------------------------- set/get Parameters ----------------------------*/
int SetCounterMode(pCounter self, CounterMode eNew);
CounterMode GetCounterMode(pCounter self);
int SetCounterPreset(pCounter self, float fVal);
float GetCounterPreset(pCounter self);
long GetCounts(pCounter self, SConnection *pCon);
long GetMonitor(pCounter self, int iNum, SConnection *pCon);
int GetNMonitor(pCounter self);
float GetCountTime(pCounter self, SConnection *pCon);
int DoCount(pCounter self,float fPreset, SConnection *pCon,
int iBlock);
/*-------------------------------------------------------------------------
the real action: starting and checking is packaged with the
ObjectDescriptor.
*/
int CountAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif

50
countf.tcl Normal file
View File

@ -0,0 +1,50 @@
#--------------------------------------------------------------------------
# A count command for FOCUS
# All arguments are optional. The current values will be used if not
# specified
# Dr. Mark Koennecke, Juli 1997
#--------------------------------------------------------------------------
proc SplitReply { text } {
set l [split $text =]
return [lindex $l 1]
}
#--------------------------------------------------------------------------
proc count { {mode NULL } { preset NULL } } {
starttime [sicstime]
#----- deal with mode
set mode2 [string toupper $mode]
set mode3 [string trim $mode2]
set mc [string index $mode2 0]
if { [string compare $mc T] == 0 } {
hm CountMode Timer
} elseif { [string compare $mc M] == 0 } {
hm CountMode Monitor
}
#------ deal with preset
if { [string compare $preset NULL] != 0 } {
hm preset $preset
}
#------ prepare a count message
set a [hm preset]
set aa [SplitReply $a]
set b [hm CountMode]
set bb [SplitReply $b]
ClientPut [format " Starting counting in %s mode with a preset of %s" \
$bb $aa]
#------- count
# hm InitVal 0
wait 1
set ret [catch {hm countblock} msg]
#------- StoreData
storefocus update
# wait 5
if { $ret != 0 } {
error [format "Counting ended with error: %s" $msg]
}
}
#---------------- Repeat -----------------------------------------------
proc repeat { num {mode NULL} {preset NULL} } {
for { set i 0 } { $i < $num } { incr i } {
count $mode $preset
}
}

16
cron.tex Normal file
View File

@ -0,0 +1,16 @@
\subsection{cron}
This module allows to install commands into SICS which will be repeated
periodically. The syntax is: sicscron intervall command. intervall is
the time intervall and command is the command to execute. A problem
is I/O becasue the original connection which installed the cron job
may be lost. Therefore cron commands are executed within the context
of special connection which does not do socket output. All I/O will be
logged into the command log though for control. As
this is a single system facility all data structure will be defined
in the implementation file. The public interface to this is just the
installation routine. This stuff is implemented in the files
sicscron.h and sicscron.c.
The installation routine installs another task into the SICS system
which will invoke the command to be executed at the predefined
intervalls.

16
cron.w Normal file
View File

@ -0,0 +1,16 @@
\subsection{cron}
This module allows to install commands into SICS which will be repeated
periodically. The syntax is: sicscron intervall command. intervall is
the time intervall and command is the command to execute. A problem
is I/O becasue the original connection which installed the cron job
may be lost. Therefore cron commands are executed within the context
of special connection which does not do socket output. All I/O will be
logged into the command log though for control. As
this is a single system facility all data structure will be defined
in the implementation file. The public interface to this is just the
installation routine. This stuff is implemented in the files
sicscron.h and sicscron.c.
The installation routine installs another task into the SICS system
which will invoke the command to be executed at the predefined
intervalls.

538
crysconv.c Normal file
View File

@ -0,0 +1,538 @@
/* crysconv.f -- translated by f2c (version 20000817).
You must link the resulting object file with the libraries:
-lf2c -lm (in that order)
*/
#include "f2c.h"
/* Common Block Declarations */
struct {
doublereal s[16] /* was [4][4] */, sinv[16] /* was [4][4] */;
integer iok;
} osolem_;
#define osolem_1 osolem_
/* ================ */
/* dec$ Ident 'V01A' */
/* ------------------------------------------------------------------ */
/* Updates: */
/* V01A 7-May-1996 DM. Put error output to IOLUN, use IMPLICIT NONE and */
/* get the code indented so that it is readable! */
/* made F77 compliant. Mark Koennecke July 1996 */
/* ------------------------------------------------------------------ */
/* Routines to deal with the reciprocical lattice PB */
/* ------------------------------------------------------------------ */
/* Entry points in this file: */
/* SETRLP : CALCULATION OF S AND INVS , ORIENTATION MATRIX */
/* RL2SPV : TRANSFO FROM RECIP LAT TO SCAT PLANE */
/* SP2RLV : TRANSFO FROM SCAT PLANE TO RECIP LAT */
/* INVS : INVERT MATRIX S, GENERATED BY SETRLP. */
/* ERRESO : DEAL ITH ERROR MESSAGES FOR ALL MODULES */
/* SUBROUTINE SETRLP(SAM,IER) */
/* SUBROUTINE RL2SPV(QHKL,QT,QM,QS,IER) */
/* SUBROUTINE SP2RLV(QHKL,QT,QM,QS,IER) */
/* SUBROUTINE INVS(S,SINV,IER) */
/* SUBROUTINE ERRESO(MODULE,IER) */
/* ------------------------------------------------------------------ */
/* Subroutine */ int setrlp_(doublereal *sam, integer *ier)
{
/* System generated locals */
doublereal d__1;
/* Builtin functions */
double cos(doublereal), sin(doublereal), sqrt(doublereal), atan(
doublereal);
/* Local variables */
static doublereal alfa[3], cosa[3], cosb[3];
static integer imod;
static doublereal sina[3], sinb[3], aspv[6] /* was [3][2] */;
extern /* Subroutine */ int invs_(doublereal *, doublereal *, integer *);
static doublereal a[3], b[3], c__[3], bb[9] /* was [3][3] */, cc;
static integer id, ie, jd, je, jf, kg, lf, lh, md, me, ne;
static doublereal zp, vv[9] /* was [3][3] */;
extern /* Subroutine */ int erreso_(integer *, integer *);
static doublereal rlb[6] /* was [3][2] */;
/* ============================ */
/* SETRLP: Computation of matrix S which transforms (QH,QK,QL) to */
/* vector (Q1,Q2) in scattering plane (defined by vectors A1,A2) */
/* and SINV matrix for the inverse transformation */
/* INPUT SAM SAMPLE CHARACTERISTICS */
/* SAM(1)=AS LATTICE PARAMETERS */
/* SAM(2)=BS ------------------ */
/* SAM(3)=CS ------------------ */
/* SAM(4)=AA LATTICE ANGLES */
/* SAM(5)=BB -------------- */
/* SAM(6)=CC -------------- */
/* SAM(7)=AX VECTOR A IN SCATTERING PLANE */
/* SAM(8)=AY ---------------------------- */
/* SAM(9)=AZ ---------------------------- */
/* SAM(10)=BX VECTOR B IN SCATTERING PLANE */
/* SAM(11)=BY ---------------------------- */
/* SAM(12)=BZ ---------------------------- */
/* OUTPUT IER ERROR RETURN TO BE TREATED BY ERRESO */
/* IER=1 ERROR ON LATTICE PARAMETERS */
/* IER=2 ERROR ON LATTICE ANGLES */
/* IER=3 ERROR ON VECTORS A1, A2 */
/* ------------------------------------------------------------------ */
/* ------------------------------------------------------------------ */
/* Define the dummy arguments */
/* ------------------------------------------------------------------ */
/* DO NOT EXPORT THE FOLLOWING COMMON ! */
/* IT IS JUST FOR PERMANENT STORAGE USE */
/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* SOME TESTS AND INIT OF CALCUALTION */
/* Parameter adjustments */
--sam;
/* Function Body */
*ier = 0;
imod = 1;
zp = 6.2831853071795862;
osolem_1.iok = 0;
for (id = 1; id <= 3; ++id) {
a[id - 1] = sam[id];
alfa[id - 1] = sam[id + 3];
aspv[id - 1] = sam[id + 6];
aspv[id + 2] = sam[id + 9];
/* L10: */
}
for (id = 1; id <= 3; ++id) {
*ier = 1;
if ((d__1 = a[id - 1], abs(d__1)) <= 1e-8) {
goto L999;
}
*ier = 0;
/* L20: */
}
for (id = 1; id <= 3; ++id) {
a[id - 1] /= zp;
alfa[id - 1] /= 57.29577951308232087679815481410517;
cosa[id - 1] = cos(alfa[id - 1]);
sina[id - 1] = sin(alfa[id - 1]);
/* L30: */
}
cc = cosa[0] * cosa[0] + cosa[1] * cosa[1] + cosa[2] * cosa[2];
cc = cosa[0] * 2. * cosa[1] * cosa[2] + 1. - cc;
*ier = 2;
if (cc <= .1) {
goto L999;
}
*ier = 0;
cc = sqrt(cc);
je = 2;
kg = 3;
for (id = 1; id <= 3; ++id) {
b[id - 1] = sina[id - 1] / (a[id - 1] * cc);
cosb[id - 1] = (cosa[je - 1] * cosa[kg - 1] - cosa[id - 1]) / (sina[
je - 1] * sina[kg - 1]);
sinb[id - 1] = sqrt(1. - cosb[id - 1] * cosb[id - 1]);
rlb[id + 2] = (d__1 = atan(sinb[id - 1] / cosb[id - 1]), abs(d__1)) *
57.29577951308232087679815481410517;
je = kg;
kg = id;
/* L40: */
}
bb[0] = b[0];
bb[1] = 0.;
bb[2] = 0.;
bb[3] = b[1] * cosb[2];
bb[4] = b[1] * sinb[2];
bb[5] = 0.;
bb[6] = b[2] * cosb[1];
bb[7] = -b[2] * sinb[1] * cosa[0];
bb[8] = 1. / a[2];
for (id = 1; id <= 3; ++id) {
rlb[id - 1] = 0.;
for (je = 1; je <= 3; ++je) {
/* Computing 2nd power */
d__1 = bb[je + id * 3 - 4];
rlb[id - 1] += d__1 * d__1;
/* L60: */
}
*ier = 1;
if ((d__1 = rlb[id - 1], abs(d__1)) <= 1e-8) {
goto L999;
}
*ier = 0;
rlb[id - 1] = sqrt(rlb[id - 1]);
/* L50: */
}
/* ----------------------------------------------------------------------- */
/* GENERATION OF S ORIENTATION MATRIX REC. LATTICE TO SCATTERING PLANE */
for (kg = 1; kg <= 2; ++kg) {
for (ie = 1; ie <= 3; ++ie) {
vv[kg + ie * 3 - 4] = 0.;
for (jf = 1; jf <= 3; ++jf) {
vv[kg + ie * 3 - 4] += bb[ie + jf * 3 - 4] * aspv[jf + kg * 3
- 4];
/* L90: */
}
/* L80: */
}
/* L70: */
}
for (md = 3; md >= 2; --md) {
for (ne = 1; ne <= 3; ++ne) {
id = md % 3 + 1;
je = (md + 1) % 3 + 1;
kg = ne % 3 + 1;
lh = (ne + 1) % 3 + 1;
vv[md + ne * 3 - 4] = vv[id + kg * 3 - 4] * vv[je + lh * 3 - 4] -
vv[id + lh * 3 - 4] * vv[je + kg * 3 - 4];
/* L110: */
}
/* L100: */
}
for (id = 1; id <= 3; ++id) {
c__[id - 1] = 0.;
for (je = 1; je <= 3; ++je) {
/* Computing 2nd power */
d__1 = vv[id + je * 3 - 4];
c__[id - 1] += d__1 * d__1;
/* L130: */
}
*ier = 3;
if ((d__1 = c__[id - 1], abs(d__1)) <= 1e-6) {
goto L999;
}
*ier = 0;
c__[id - 1] = sqrt(c__[id - 1]);
/* L120: */
}
for (id = 1; id <= 3; ++id) {
for (je = 1; je <= 3; ++je) {
vv[je + id * 3 - 4] /= c__[je - 1];
/* L160: */
}
/* L150: */
}
for (kg = 1; kg <= 3; ++kg) {
for (me = 1; me <= 3; ++me) {
osolem_1.s[kg + (me << 2) - 5] = 0.;
for (lf = 1; lf <= 3; ++lf) {
osolem_1.s[kg + (me << 2) - 5] += vv[kg + lf * 3 - 4] * bb[lf
+ me * 3 - 4];
/* L190: */
}
/* L180: */
}
/* L170: */
}
osolem_1.s[15] = 1.;
for (jd = 1; jd <= 3; ++jd) {
osolem_1.s[(jd << 2) - 1] = 0.;
osolem_1.s[jd + 11] = 0.;
/* L200: */
}
/* ----------------------------------------------------------------------- */
/* INVERT TRANSFORMATION MATRIX S AND PU RESULT IN SINV */
*ier = 3;
invs_(osolem_1.s, osolem_1.sinv, ier);
*ier = 0;
if (*ier != 0) {
goto L999;
}
osolem_1.iok = 123;
/* --------------------------------------------------------------------------- */
/* SORTIE */
L999:
if (*ier != 0) {
erreso_(&imod, ier);
}
return 0;
} /* setrlp_ */
/* =========================================================================== */
/* Subroutine */ int rl2spv_(doublereal *qhkl, doublereal *qt, doublereal *qm,
doublereal *qs, integer *ier)
{
/* System generated locals */
doublereal d__1;
/* Builtin functions */
double sqrt(doublereal);
/* Local variables */
static integer id, je;
/* ========================================= */
/* ------------------------------------------------------------------ */
/* INPUT QHKL QHKL -> QT */
/* A Q-VECTOR TO BE TRANSFORM FROM RECIP LATTICE TO SCATTERING PLANE */
/* CHECK THAT Q-VECTOR IS IN THE PLANE */
/* INPUT Q-VECTOR QHKL(3) Q-VECTOR IN RECIPROCICAL LATTICVE */
/* OUTPUT Q-VECTOR QT(3) Q-VECTOR IN SCATTERING PLANE */
/* OUTPUT QM AND QS QMODULUS AND ITS SQUARE ( TO BE VERIFIED ) */
/* OUTPUT ERROR IER */
/* IER=1 MATRIX S NOT OK */
/* IER=2 Q NOT IN SCATTERING PLANE */
/* IER=3 Q MODULUS TOO SMALL */
/* ------------------------------------------------------------------ */
/* ------------------------------------------------------------------ */
/* Define the dummy arguments */
/* ------------------------------------------------------------------ */
/* DO NOT EXPORT THE FOLLWING COOMON ! */
/* IT IS JUST FOR PERMANENT STORAGE USE */
/* --------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------- */
/* INIT AND TEST IF TRANSFO MATRICES ARE OK */
/* Parameter adjustments */
--qt;
--qhkl;
/* Function Body */
*ier = 1;
if (osolem_1.iok != 123) {
goto L999;
}
*ier = 0;
/* ----------------------------------------------------------------------- */
for (id = 1; id <= 3; ++id) {
qt[id] = 0.;
for (je = 1; je <= 3; ++je) {
qt[id] += qhkl[je] * osolem_1.s[id + (je << 2) - 5];
/* L20: */
}
/* L10: */
}
*ier = 2;
if (abs(qt[3]) > 1e-4) {
goto L999;
}
*ier = 0;
*qs = 0.;
for (id = 1; id <= 3; ++id) {
/* Computing 2nd power */
d__1 = qt[id];
*qs += d__1 * d__1;
/* L30: */
}
if (*qs < 1e-8) {
*ier = 3;
} else {
*qm = sqrt(*qs);
}
/* --------------------------------------------------------------------------- */
L999:
return 0;
} /* rl2spv_ */
/* =========================================================================== */
/* Subroutine */ int sp2rlv_(doublereal *qhkl, doublereal *qt, doublereal *qm,
doublereal *qs, integer *ier)
{
/* System generated locals */
doublereal d__1;
/* Builtin functions */
double sqrt(doublereal);
/* Local variables */
static integer id, je;
/* ========================================= */
/* ------------------------------------------------------------------ */
/* INPUT QT QHKL <- QT */
/* A Q-VECTOR TO BE TRANSFORM FROM SCATTERING PLANE TO RECIP LATTICE */
/* CHECK THAT Q, D & G VECTORS ARE IN THE SCATTERING PLANE */
/* INPUT Q-VECTOR QT(3) Q-VECTOR IN SCATTERING PLANE */
/* OUTPUT Q-VECTOR QHKL(3) Q-VECTOR IN RECIPROCICAL LATTICVE */
/* OUTPUT QM AND QS QMODULUS AND ITS SQUARE ( TO BE VERIFIED ) */
/* OUTPUT ERROR IER */
/* IER=1 MATRIX S NOT OK */
/* IER=2 Q NOT IN SCATTERING PLANE */
/* IER=3 Q MODULUS TOO SMALL */
/* ------------------------------------------------------------------ */
/* ------------------------------------------------------------------ */
/* Define the dummy arguments */
/* ------------------------------------------------------------------ */
/* DO NOT EXPORT THE FOLLWING COOMON ! */
/* IT IS JUST FOR PERMANENT STORAGE USE */
/* --------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------- */
/* INIT AND TEST IF TRANSFO MATRICES ARE OK */
/* Parameter adjustments */
--qt;
--qhkl;
/* Function Body */
*ier = 1;
if (osolem_1.iok != 123) {
goto L999;
}
*ier = 2;
if (abs(qt[3]) > 1e-4) {
goto L999;
}
*ier = 0;
/* ----------------------------------------------------------------------- */
*qs = 0.;
for (id = 1; id <= 3; ++id) {
/* Computing 2nd power */
d__1 = qt[id];
*qs += d__1 * d__1;
/* L10: */
}
if (*qs < 1e-8) {
*ier = 3;
} else {
*qm = sqrt(*qs);
}
/* ----------------------------------------------------------------------- */
for (id = 1; id <= 3; ++id) {
qhkl[id] = 0.;
for (je = 1; je <= 3; ++je) {
qhkl[id] += osolem_1.sinv[id + (je << 2) - 5] * qt[je];
/* L30: */
}
/* L20: */
}
/* --------------------------------------------------------------------------- */
L999:
return 0;
} /* sp2rlv_ */
/* ========================================================================== */
/* Subroutine */ int invs_(doublereal *s, doublereal *sinv, integer *ier)
{
/* Initialized data */
static integer m[3] = { 2,3,1 };
static integer n[3] = { 3,1,2 };
static integer id, je, mi, mj, ni, nj;
static doublereal det;
/* ============================== */
/* ------------------------------------------------------------------ */
/* ROUTINE TO INVERT MATRIX S, GENERATED BY SETRLP, WHICH TRANSFORMS */
/* (QH,QK,QL) TO (Q1,Q2) IN THE SCATTERING PLANE */
/* INPUT MATRIX DOUBLE PRECISION S(4,4) */
/* OUTPUT MATRIX DOUBLE PRECISION SINV(4,4) */
/* OUTPUT ERROR IER */
/* IER=1 DETERMINANT OF MATRIX S TOO SMALL */
/* ------------------------------------------------------------------ */
/* ------------------------------------------------------------------ */
/* Define the dummy arguments */
/* ------------------------------------------------------------------ */
/* Parameter adjustments */
sinv -= 5;
s -= 5;
/* Function Body */
/* ------------------------------------------------------------------ */
*ier = 0;
for (id = 1; id <= 4; ++id) {
for (je = 1; je <= 4; ++je) {
sinv[id + (je << 2)] = 0.;
/* L20: */
}
/* L10: */
}
det = 0.;
for (id = 1; id <= 3; ++id) {
for (je = 1; je <= 3; ++je) {
mi = m[id - 1];
mj = m[je - 1];
ni = n[id - 1];
nj = n[je - 1];
sinv[je + (id << 2)] = s[mi + (mj << 2)] * s[ni + (nj << 2)] - s[
ni + (mj << 2)] * s[mi + (nj << 2)];
/* L40: */
}
det += s[id + 4] * sinv[(id << 2) + 1];
/* L30: */
}
if (abs(det) < 1e-6) {
*ier = 1;
} else {
for (id = 1; id <= 3; ++id) {
for (je = 1; je <= 3; ++je) {
sinv[id + (je << 2)] /= det;
/* L70: */
}
/* L60: */
}
}
sinv[20] = 1.;
return 0;
} /* invs_ */
/* ========================================================================= */
/* Subroutine */ int erreso_(integer *module, integer *ier)
{
/* System generated locals */
integer i__1;
/* Local variables */
static integer lmod, lier;
/* ============================= */
/* ------------------------------------------------------------------ */
/* SUBROUTINE TO TREAT ERRORS FROM RESOLUTION CALCULATIONS */
/* MODULE = 1 -> SETRLP */
/* MODULE = 2 -> RL2SPV */
/* MODULE = 3 -> EX_CASE */
/* ------------------------------------------------------------------ */
/* INCLUDE 'MAD_DEF:IOLSDDEF.INC' */
/* ------------------------------------------------------------------ */
/* Define the dummy arguments */
/* ------------------------------------------------------------------ */
/* --------------------------------------------------------------------------- */
/* Computing MIN */
i__1 = max(*ier,1);
lier = min(i__1,4);
/* Computing MIN */
i__1 = max(*module,1);
lmod = min(i__1,3);
/* WRITE(6,501) MESER(LIER,LMOD) */
/* 501 FORMAT(A) */
return 0;
} /* erreso_ */

114
cryst.c Normal file
View File

@ -0,0 +1,114 @@
/*---------------------------------------------------------------------------
C r y s t
This is a library of crystallographic utility routines for four
circle diffractometers. It deals with all sorts of rotations and
stuff. This is based on code originally developed by John Allibon
at ILL and reimplemented in C using a matrix-library.
Mark Koennecke, July 2000
----------------------------------------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include "matrix/matrix.h"
#include "cryst.h"
#define PIR 57.30
/*-------------------------------------------------------------------------
chimat, calculate chi rotation matrix. The input angle is in degrees.
The setting is Busing & Levy.
--------------------------------------------------------------------------*/
MATRIX chimat(double dAngle)
{
MATRIX res;
double dChi;
res = mat_creat(3,3,ZERO_MATRIX);
dChi = dAngle/PIR;
res[0][0] = cos(dChi);
res[0][2] = sin(dChi);
res[1][1] = 1.;
res[2][0] = -res[0][2];
res[2][2] = res[0][0];
return res;
}
/*-------------------------------------------------------------------------
phimat, calculate phi rotation matrix. The input angle is in degrees.
The setting is Busing & Levy.
--------------------------------------------------------------------------*/
MATRIX phimat(double dAngle)
{
MATRIX res;
double dPhi;
res = mat_creat(3,3,ZERO_MATRIX);
dPhi = dAngle/PIR;
res[0][0] = cos(dPhi);
res[0][1] = sin(dChi);
res[2][2] = 1.;
res[1][0] = -res[0][1];
res[1][1] = res[0][0];
return res;
}
/*-------------------------------------------------------------------------
psimat, calculate psi rotation matrix. The input angle is in degrees.
The setting is Busing & Levy.
--------------------------------------------------------------------------*/
MATRIX psimat(double dAngle)
{
MATRIX res;
double dPsi;
res = mat_creat(3,3,ZERO_MATRIX);
dPsi = dAngle/PIR;
res[0][0] = 1.;
res[1][1] = cos(dPsi);
res[1][2] = -sin(dPsi);
res[2][1] = -res[1][2];
res[2][2] = res[1][1];
return res;
}
/*-------------------------------------------------------------------------
diffFromAngles calculates the diffraction vector from two theta, omega
chi and phi. The angled need not be bissecting but it is assumed that
the diffraction vector is in the equatorial plane.
--------------------------------------------------------------------------*/
MATRIX diffFromAngles(double wave, double tth, double om,
double chi, double phi)
{
MATRIX res, rot, dum, z;
double dTh;
dTh = (tth/2.)/PIR;
res = mat_creat(3,1,ZERO_MATRIX);
res[0][0] = (2.*sin(dTh)*cos(dTh))/wave;
res[1][0] = (-2. *sin(dTh)*sin(dTh))/wave;
/* undo omega rotation */
rot = phimat(om);
dum = mat_tran(rot);
mat_free(rot);
z = mat_mul(dum,res);
mat_free(dum);
mat_free(res);
/* result is now z */
}

46
d_mod.c Normal file
View File

@ -0,0 +1,46 @@
#include "f2c.h"
#ifdef KR_headers
#ifdef IEEE_drem
double drem();
#else
double floor();
#endif
double d_mod(x,y) doublereal *x, *y;
#else
#ifdef IEEE_drem
double drem(double, double);
#else
#undef abs
#include "math.h"
#ifdef __cplusplus
extern "C" {
#endif
#endif
double d_mod(doublereal *x, doublereal *y)
#endif
{
#ifdef IEEE_drem
double xa, ya, z;
if ((ya = *y) < 0.)
ya = -ya;
z = drem(xa = *x, ya);
if (xa > 0) {
if (z < 0)
z += ya;
}
else if (z > 0)
z -= ya;
return z;
#else
double quotient;
if( (quotient = *x / *y) >= 0)
quotient = floor(quotient);
else
quotient = -floor(-quotient);
return(*x - (*y) * quotient );
#endif
}
#ifdef __cplusplus
}
#endif

18
d_sign.c Normal file
View File

@ -0,0 +1,18 @@
#include "f2c.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef KR_headers
double d_sign(a,b) doublereal *a, *b;
#else
double d_sign(doublereal *a, doublereal *b)
#endif
{
double x;
x = (*a >= 0 ? *a : - *a);
return( *b >= 0 ? x : -x);
}
#ifdef __cplusplus
}
#endif

293
danu.c Normal file
View File

@ -0,0 +1,293 @@
/*-----------------------------------------------------------------------
D A T A N U M B E R
Implementation file for the data number module.
Mark Koennecke, Juli 1997
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <assert.h>
#include "fortify.h"
#include "conman.h"
#include "obdes.h"
#include "danu.h"
/* ------------------ the data structure ----------------------------------*/
typedef struct __DataNumber {
pObjectDescriptor pDes;
char *pFileName;
} DataNumber;
/*-------------------------------------------------------------------------*/
pDataNumber CreateDataNumber(char *pFileName)
{
pDataNumber pNew = NULL;
FILE *fd = NULL;
pNew = (pDataNumber)malloc(sizeof(DataNumber));
if(!pNew)
{
return NULL;
}
memset(pNew,0,sizeof(DataNumber));
pNew->pDes = CreateDescriptor("DataNumber");
if(!pNew->pDes)
{
free(pNew);
return NULL;
}
/* check filename */
fd = fopen(pFileName,"r");
if(!fd)
{
printf("Serious error: cannot open file for Data Number!!!!\n");
printf("I continue, but you should not write data files!\n");
pNew->pFileName = strdup("default.num");
return pNew;
}
fclose(fd);
pNew->pFileName = strdup(pFileName);
return pNew;
}
/*--------------------------------------------------------------------------*/
void DeleteDataNumber(void *pData)
{
pDataNumber self = NULL;
self = (pDataNumber)pData;
assert(self);
if(self->pDes)
{
DeleteDescriptor(self->pDes);
}
if(self->pFileName)
{
free(self->pFileName);
}
free(self);
}
/*-------------------------------------------------------------------------*/
int IncrementDataNumber(pDataNumber self, int *iYear)
{
FILE *fd = NULL;
int iNum;
time_t iTime;
struct tm *psTime;
/* open file */
fd = fopen(self->pFileName,"r");
if(!fd)
{
return -1;
}
/* get and increment number */
fscanf(fd,"%d",&iNum);
iNum++;
fclose(fd);
/* reopen for rewriting */
fd = fopen(self->pFileName,"w");
if(fd == NULL)
{
return -1;
}
/* write file and leave */
fprintf(fd," %d \n",iNum);
fprintf(fd,"NEVER, EVER modify or delete this file\n");
fprintf(fd,"You'll risk eternal damnation and a reincarnation as a cockroach!|n");
fclose(fd);
/* get year */
iTime = time(NULL);
psTime = localtime(&iTime);
*iYear = psTime->tm_year + 1900;
return iNum;
}
/*-------------------------------------------------------------------------*/
int DecrementDataNumber(pDataNumber self)
{
FILE *fd = NULL;
int iNum;
/* open file */
fd = fopen(self->pFileName,"r");
if(!fd)
{
return -1;
}
/* get and decrement number */
fscanf(fd,"%d",&iNum);
iNum--;
if(iNum < 0)
iNum = 0;
fclose(fd);
/* reopen for rewriting */
fd = fopen(self->pFileName,"w");
/* write file and leave */
fprintf(fd," %d \n",iNum);
fprintf(fd,"NEVER, EVER modify or delete this file\n");
fprintf(fd,"You'll risk eternal damnation and a reincarnation as a cockroach!|n");
fclose(fd);
return iNum;
}
/*-------------------------------------------------------------------------*/
int DNWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pDataNumber self = NULL;
FILE *fd = NULL;
int iNum, iYear;
char pBueffel[512];
self = (pDataNumber)pData;
assert(self);
assert(pCon);
argtolower(argc,argv);
if(argc < 2) /* value request */
{
fd = fopen(self->pFileName,"r");
if(!fd)
{
sprintf(pBueffel,"ERROR: cannot open file %s",self->pFileName);
SCWrite(pCon,pBueffel,eError);
return 0;
}
fscanf(fd,"%d",&iNum);
fclose(fd);
sprintf(pBueffel,"%s = %d",argv[0],iNum);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
if(strcmp(argv[1],"incr") == 0)
{
iNum = IncrementDataNumber(self,&iYear);
if(iNum > 0)
{
SCSendOK(pCon);
return 1;
}
else
{
sprintf(pBueffel,"ERROR: cannot increment %s",argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
}
sprintf(pBueffel,"ERROR: unknown command %s supplied to %s",
argv[1], argv[0]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/*------------------------------------------------------------------------*/
int DEWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pDataNumber self = NULL;
int iNum;
char pBueffel[512];
self = (pDataNumber)pData;
assert(self);
assert(pCon);
if(SCMatchRights(pCon,usMugger))
{
DecrementDataNumber(self);
SCWrite(pCon,"Data file killed",eWarning);
return 1;
}
else
{
SCWrite(pCon,"ERROR: you are not authorized to kill data files",
eError);
return 0;
}
}
/*-------------------------------------------------------------------------*/
int DNFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pDataNumber self = NULL;
char pBueffel[512];
int iRet;
if(argc < 3)
{
SCWrite(pCon,
"ERROR: not enough arguments provided to make DataNumber",eError);
return 0;
}
self = CreateDataNumber(argv[2]);
if(!self)
{
SCWrite(pCon,"ERROR: no memory to create data number",eError);
return 0;
}
iRet = AddCommand(pSics, argv[1],DNWrapper, DeleteDataNumber, self);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = AddCommand(pSics,"killfile",DEWrapper,NULL, self);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
return 1;
}

3
danu.dat Normal file
View File

@ -0,0 +1,3 @@
286
NEVER, EVER modify or delete this file
You'll risk eternal damnation and a reincarnation as a cockroach!|n

41
danu.h Normal file
View File

@ -0,0 +1,41 @@
#line 53 "danu.w"
/*-----------------------------------------------------------------------
D A T A N U M B E R
A module to provide a unique data number for data file writing.
Mark Koennecke, Juli 1997
copyright: see implementation file.
---------------------------------------------------------------------------*/
#ifndef SICSDATANUMBER
#define SICSDATANUMBER
#line 15 "danu.w"
typedef struct __DataNumber *pDataNumber;
pDataNumber CreateDataNumber(char *pFilename);
void DeleteDataNumber(void *pData);
int IncrementDataNumber(pDataNumber self, int *iYear);
int DecrementDataNumber(pDataNumber self);
int DNWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int DEWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int DNFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#line 67 "danu.w"
#endif

Some files were not shown because too many files have changed in this diff Show More