- Added separate drivable motors for four circle H, K, L

- Added a listen mode to commandlog in order to support the batchEditor
- Some small fixes to exe* for BatchEditor
This commit is contained in:
koennecke
2005-02-23 10:11:18 +00:00
parent ef1de4589c
commit 28ddbc420d
39 changed files with 1274 additions and 130 deletions

View File

@ -421,7 +421,12 @@ extern char *SkipSpace(char *pPtr);
pTcl = (Tcl_Interp *)self->pTcl;
if(pTcl)
{
/*
uncommented: the current versions of Tcl (8.3,4) dump core with a
memory problem deep in the Tcl library. This causes a core dump on
each SICS restart and breaks the use of external tools.
Tcl_DeleteInterp(pTcl);
*/
}
free(self);

View File

@ -161,8 +161,6 @@
{
self->pDriv->Close(self->pDriv);
self->pDriv->Delete(self->pDriv);
if(self->pDriv->pParList)
free(self->pDriv->pParList);
free(self->pDriv);
}
if(self->pDes)

View File

@ -27,8 +27,6 @@
/* in conman.c */
int TelnetWrite(mkChannel *pSock, char *pText);
/*-------------------- the command log file pointer ---------------------*/
static FILE *fd = NULL;
static FILE *fauto = NULL;
@ -122,6 +120,13 @@
fprintf(fauto,"%s %s\n",prompt, pText);
}
}
/* to all listening sockets. The check is necessary to resolve a shutdown problem */
if(pServ->pTasker != NULL)
{
TaskSignal(pServ->pTasker,COMLOG,pText);
}
/* tail buffer */
if(pTail != NULL)
{

View File

@ -103,6 +103,7 @@ extern pServer pServ;
memset(pCon,0,sizeof(SConnection));
pCon->ident = 0;
pCon->next = freeConnections;
pCon->listening = 0;
freeConnections = pCon;
}
/*--------------------------------------------------------------------------*/
@ -174,6 +175,7 @@ extern pServer pServ;
pRes->eInterrupt = eContinue;
pRes->lMagic = CONMAGIC;
pRes->iLogin = 0;
pRes->listening = 0;
pRes->conStart = time(NULL);
pRes->write = SCNormalWrite;
for(i = 0; i < 10; i++)
@ -203,11 +205,6 @@ extern pServer pServ;
pRes->iUserRights = iUser;
pRes->iGrab = TokenGrabActive();
NETInfo(pRes->pSock,pHost,131);
sprintf(pBueffel,"Accepted connection on socket %d from %s",
pRes->pSock->sockid, pHost);
SICSLogWrite(pBueffel,eInternal);
WriteToCommandLog("SYS >", pBueffel);
return pRes;
@ -395,7 +392,7 @@ extern pServer pServ;
}
/* log the kill */
if(pVictim->pSock)
if(pVictim->pSock && pVictim->iLogin == 1)
{
sprintf(pBueffel,"Deleting connection %d",pVictim->pSock->sockid);
WriteToCommandLog("SYS>",pBueffel);
@ -599,7 +596,9 @@ static int doSockWrite(SConnection *self, char *buffer)
if(!iRet)
{
SCnoSock(self);
WriteToCommandLog("SYS> ","Connection broken on send");
if(!self->listening && self->iLogin == 1){
WriteToCommandLog("SYS> ","Connection broken on send");
}
}
}
else
@ -1358,6 +1357,7 @@ static void writeToLogFiles(SConnection *self, char *buffer)
config Rights User Password sets and verifies new user rights
config File Filename Logs to another file
config output normal | withcode Sets output mode
config listen 0 | 1 enables commandlog listen mode
---------------------------------------------------------------------------*/
int ConfigCon(SConnection *pCon, SicsInterp *pSics, void *pData,
@ -1402,6 +1402,27 @@ static void writeToLogFiles(SConnection *self, char *buffer)
SCWrite(pCon,pBueffel,eValue);
return 1;
}
else if(strcmp(argv[1],"listen") == 0)
{
if(argc < 3)
{
snprintf(pBueffel,511,"listen = %d", pCon->listening);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
else
{
pCon->listening = atoi(argv[2]);
if(pCon->listening != 0 && pCon->listening != 1)
{
pCon->listening = 0;
SCWrite(pCon,"ERROR: config listen only accepts 0 or 1 as arguments",eError);
return 0;
}
SCSendOK(pCon);
return 1;
}
}
/* check no or args */
if(argc < 3)
@ -1747,6 +1768,7 @@ static void writeToLogFiles(SConnection *self, char *buffer)
char *pPtr = NULL;
int iRet;
char *pUser = NULL, *pPassword = NULL;
char pHost[132], pBueffel[512];
self = (SConnection *)pData;
if(!VerifyConnection(self))
@ -1810,6 +1832,11 @@ static void writeToLogFiles(SConnection *self, char *buffer)
SCWrite(self,"Login OK",eError);
self->iLogin = 1;
SCSetRights(self,iRet);
NETInfo(self->pSock,pHost,131);
sprintf(pBueffel,"Accepted connection on socket %d from %s",
self->pSock->sockid, pHost);
SICSLogWrite(pBueffel,eInternal);
WriteToCommandLog("SYS >", pBueffel);
free(pPtr);
return 1;
}
@ -1863,11 +1890,19 @@ static void writeToLogFiles(SConnection *self, char *buffer)
else if(iSignal == SICSBROADCAST)
{
pPtr = (char *)pSigData;
if(pPtr)
if(pPtr != NULL)
{
SCWrite(self,pPtr,eWarning);
}
}
else if(iSignal == COMLOG && self->listening == 1)
{
pPtr = (char *)pSigData;
if(pPtr != NULL)
{
doSockWrite(self,pPtr);
}
}
else if(iSignal == TOKENRELEASE)
{
self->iGrab = 0;

View File

@ -49,6 +49,7 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
int iOutput;
writeFunc write; /* function doing
writing */
int listening; /* for listening to commandlog or other data */
/* execution context */
int eInterrupt;
@ -72,8 +73,7 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
*/
int iLogin;
time_t conStart;
} SConnection;
} SConnection;
#include "nserver.h"

View File

@ -103,6 +103,7 @@
if(iRet == OKOK)
{
self->isUpToDate = 0;
self->badStatusCount = 0;
self->tStart = time(&tX);
InvokeCallBack(self->pCall,COUNTSTART,pCon);
return iRet;
@ -224,11 +225,12 @@
eCt = self->pDriv->GetStatus(self->pDriv,&fControl);
if(eCt == HWFault)
{
self->badStatusCount++;
iRet = self->pDriv->GetError(self->pDriv,&iErr,pError,79);
sprintf(pBueffel,"WARNING: %s ",pError);
SCWrite(pCon,pBueffel,eError);
iRet = self->pDriv->TryAndFixIt(self->pDriv,iErr);
if(iRet == COTERM)
if(iRet == COTERM || self->badStatusCount > 3)
{
SCWrite(pCon,"ERROR: Cannot fix counter problem, aborting",eError);
SCSetInterrupt(pCon,eAbortBatch);
@ -247,6 +249,7 @@
sMon.fCurrent = fControl;
sMon.fPreset = self->pDriv->fPreset;
sMon.pName = self->name;
self->badStatusCount = 0; /* clear: we managed to read OK */
if(self->iCallbackCounter > 20)
{
InvokeCallBack(self->pCall,MONITOR,&sMon);

View File

@ -23,6 +23,7 @@
pICallBack pCall;
unsigned long tStart;
int iCallbackCounter;
int badStatusCount;
} Counter, *pCounter;
/*----------------------------- birth & death -----------------------------*/

365
diffscan.c Normal file
View File

@ -0,0 +1,365 @@
/*-------------------------------------------------------------------
diffscan is an operator which can perform a fast differential scan
while a motor is running.
copyright: see file COPYRIGHT
Mark Koennecke, November 2004
---------------------------------------------------------------------*/
#include <stdio.h>
#include <assert.h>
#include <tcl.h>
#include "fortify.h"
#include "sics.h"
#include "diffscan.h"
#include "drive.h"
#include "counter.h"
#define DIFFMONITOR 0
#define SKIP 1
/*-------------------------------------------------------------------*/
static void KillDiffScan(void *data){
pDiffScan self = (pDiffScan)data;
if(self == NULL){
return;
}
if(self->pDes != NULL){
DeleteDescriptor(self->pDes);
}
if(self->parArray != NULL){
ObParDelete(self->parArray);
}
free(self);
}
/*---------------------------------------------------------------------*/
static int SaveDiffScan(void *data, char *name, FILE *fd){
pDiffScan self = (pDiffScan)data;
if(self == NULL){
return 0;
}
fprintf(fd,"%s monitor %f\n",name,ObVal(self->parArray,DIFFMONITOR));
fprintf(fd,"%s skip %f\n",name,ObVal(self->parArray,SKIP));
return 1;
}
/*----------------------------------------------------------------------*/
int MakeDiffScan(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pDiffScan pNew = NULL;
int status;
pNew = (pDiffScan)malloc(sizeof(DiffScan));
if(pNew == NULL){
SCWrite(pCon,"ERROR: out of memory creating differential scan",
eError);
return 0;
}
memset(pNew,0,sizeof(DiffScan));
pNew->pDes = CreateDescriptor("DiffScan");
pNew->parArray = ObParCreate(2);
if(!pNew->pDes || !pNew->parArray){
SCWrite(pCon,"ERROR: out of memory creating differential scan",
eError);
KillDiffScan(pNew);
return 0;
}
ObParInit(pNew->parArray, DIFFMONITOR,"monitor",4.0,usUser);
ObParInit(pNew->parArray, SKIP,"skip",.0,usUser);
pNew->pDes->SaveStatus = SaveDiffScan;
if(argc > 1) {
status = AddCommand(pSics,argv[2],
DiffScanWrapper,
KillDiffScan,
pNew);
} else {
status = AddCommand(pSics,"diffscan",
DiffScanWrapper,
KillDiffScan,
pNew);
}
if(status != 1){
SCWrite(pCon,"ERROR: duplicate diffscan not created",eError);
return 0;
}
return 1;
}
/*----------------------------------------------------------------------*/
int DiffScanWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pDiffScan self = NULL;
pScanData pScan = NULL;
ObPar *par = NULL;
char pBueffel[255];
int status;
self = (pDiffScan)pData;
assert(self);
if(argc < 2){
SCWrite(pCon,"ERROR: need arguments to diffscan",eError);
return 0;
}
if(!SCMatchRights(pCon,usUser)){
return 0;
}
/*
first try to find a scan object and to run
*/
strtolower(argv[1]);
pScan = (pScanData)FindCommandData(pSics,argv[1],"ScanObject");
if(pScan != NULL && argc > 2){
status = RunDiffScan(self,pScan,pCon, atof(argv[2]));
return status;
}
/*
if we end here we are treating variables
*/
if(argc > 2){
/*
set case
*/
return ObParSet(self->parArray,argv[0],argv[1],atof(argv[2]),pCon);
} else {
/*
get case
*/
par = ObParFind(self->parArray,argv[1]);
if(par != NULL){
snprintf(pBueffel,255,"%s.%s = %f",argv[0],argv[1],par->fVal);
SCWrite(pCon,pBueffel,eValue);
return 1;
} else {
snprintf(pBueffel,255,"ERROR: parameter %s not found",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
}
return 1;
}
/*--------------------------------------------------------------------*/
static int StartDiffScan(pDiffScan self, pScanData pScan,
SConnection *pCon, float fEnd){
pVarEntry pVar = NULL;
void *pPtr = NULL;
pCounter pCount = NULL;
char pBueffel[255];
int status;
/*
error checks
*/
if(pScan->iScanVar < 1) {
SCWrite(pCon,"ERROR: no scan variable to diffscan",eError);
return 0;
}
if(pScan->iScanVar > 1) {
snprintf(pBueffel,255,
"WARNING: diffscan handles only first scan variable, %d %s",
pScan->iScanVar - 1,
"scan variables ignored");
SCWrite(pCon,pBueffel, eWarning);
}
/*
initialize data structure
*/
self->scanObject = pScan;
self->scanObject->pCon = pCon;
self->skip = (int)ObVal(self->parArray,SKIP);
self->scaleMonitor = (int)ObVal(self->parArray,DIFFMONITOR);
self->normalizationScale = -1;
pScan->iCounts = 0;
/*
get variable
*/
DynarGet(pScan->pScanVar,0,&pPtr);
pVar = (pVarEntry)pPtr;
if(pVar == NULL){
SCWrite(pCon,"ERROR: cannot access scan variable",eError);
return 0;
}
/*
drive to start position
*/
status = Drive(pCon,pServ->pSics,ScanVarName(pVar),ScanVarStart(pVar));
if(status != 1){
return 0;
}
/*
Configure counter. We operate in timer mode with a very long
preset mode. Stopping is done explicitly in the diffscan task
*/
SetCounterMode(pScan->pCounterData,eTimer);
SetCounterPreset(pScan->pCounterData,3600.);
/*
start motor and counter
*/
status = pVar->pInter->SetValue(pVar->pObject,pCon,fEnd);
if(status != OKOK){
/*
errors will already have been reported in SetValue
*/
return 0;
}
pCount = (pCounter)pScan->pCounterData;
assert(pCount);
status = pCount->pCountInt->StartCount(pCount,pCon);
if(status != OKOK){
return 0;
}
return 1;
}
/*--------------------------------------------------------------------*/
static float normalizeEntry(pCountEntry pCount, pCountEntry last,
long monValue, int scaleMon){
int i;
float fScale;
float value;
long diff;
/*
calculate scale
*/
diff = pCount->Monitors[scaleMon-1] - last->Monitors[scaleMon-1];
if(diff > 0) {
fScale = (float)monValue/(float)diff;
} else {
fScale = 0.;
}
value = ((float)(pCount->lCount - last->lCount))*fScale;
pCount->lCount = (long)value;
for(i = 0; i < 10; i++){
pCount->Monitors[i] = (pCount->Monitors[i] - last->Monitors[i])*fScale;
}
return value;
}
/*--------------------------------------------------------------------*/
static void copyCountData(pCountEntry last, pCountEntry pCount){
memcpy(last,pCount,sizeof(CountEntry));
}
/*---------------------------------------------------------------------*/
static int DiffScanTask(void *pData){
pCounter pCount = NULL;
pCountEntry data;
pVarEntry pVar = NULL;
void *pPtr = NULL;
float fPos, countValue;
int status, finish = 1, count;
char pBueffel[255];
long rawCount, rawMon;
CountEntry rawCopy;
pDiffScan self = (pDiffScan)pData;
/*
manage skip
*/
if(self->skip > 0){
if(self->skipCount > self->skip){
self->skipCount = 0;
} else {
self->skipCount++;
return 1;
}
}
/*
read motor status
*/
DynarGet(self->scanObject->pScanVar,0,&pPtr);
pVar = (pVarEntry)pPtr;
status = pVar->pInter->CheckStatus(pVar->pObject,self->scanObject->pCon);
if(status != HWBusy) {
finish = 0;
}
/*
read values
*/
status = GetDrivablePosition(pVar->pObject,self->scanObject->pCon,
&fPos);
if(status == 0){
return finish;
}
AppendScanVar(pVar,fPos);
pCount = (pCounter)self->scanObject->pCounterData;
pCount->pCountInt->TransferData(pCount,self->scanObject->pCon);
CollectCounterData(self->scanObject);
/*
normalize (or not)
*/
DynarGet(self->scanObject->pCounts,self->scanObject->iCounts-1,&pPtr);
data = (pCountEntry)pPtr;
copyCountData(&rawCopy,data);
if(self->normalizationScale < 0){
countValue = (float)data->lCount;
rawCount = data->lCount;
rawMon = data->Monitors[self->scaleMonitor-1];
self->normalizationScale = data->Monitors[self->scaleMonitor-1];
} else {
if(data->Monitors[self->scaleMonitor -1] -
self->last.Monitors[self->scaleMonitor-1] < 5) {
SCWrite(self->scanObject->pCon,
"WARNING: low count rate",eWarning);
}
rawCount = data->lCount;
rawMon = data->Monitors[self->scaleMonitor-1];
countValue = normalizeEntry(data,&self->last,
self->normalizationScale,
self->scaleMonitor);
}
copyCountData(&self->last,&rawCopy);
/*
print progress
*/
snprintf(pBueffel,255,"%5d %12.4f %12.4f RAW: %10d %10d",
self->scanObject->iCounts -1,
fPos, countValue, rawCount,
rawMon);
SCWrite(self->scanObject->pCon,pBueffel,eWarning);
InvokeCallBack(self->scanObject->pCall,SCANPOINT,self->scanObject);
/*
check for interrupt
*/
if(SCGetInterrupt(self->scanObject->pCon) >= eAbortScan){
finish = 0;
}
return finish;
}
/*----------------------------------------------------------------------*/
int RunDiffScan(pDiffScan self, pScanData pScan,
SConnection *pCon, float fEnd){
long lID;
pCounter pCount = NULL;
if(StartDiffScan(self,pScan,pCon,fEnd) != 1) {
return 0;
}
InvokeCallBack(self->scanObject->pCall,SCANSTART,self->scanObject);
lID = TaskRegister(pServ->pTasker,DiffScanTask,NULL,NULL,self,10);
TaskWait(pServ->pTasker,lID);
pCount = (pCounter)self->scanObject->pCounterData;
pCount->pCountInt->Halt(pCount);
InvokeCallBack(self->scanObject->pCall,SCANEND,self->scanObject);
return 1;
}

47
diffscan.h Normal file
View File

@ -0,0 +1,47 @@
/*-------------------------------------------------------------------
diffscan is an operator which can perform a fast differential scan
while a motor is running.
copyright: see file COPYRIGHT
Mark Koennecke, November 2004
---------------------------------------------------------------------*/
#ifndef SICSDIFFSCAN
#define SICSDIFFSCAN
#include "obpar.h"
#include "scan.h"
#include "scan.i"
typedef struct {
pObjectDescriptor pDes;
ObPar *parArray;
int normalizationScale;
int scaleMonitor;
CountEntry last;
int skip;
int skipCount;
pScanData scanObject;
} DiffScan, *pDiffScan;
/*==================================================================*/
/**
* RunDiffScan runs a differential scan.
* @param self The Diffscan object to use
* @param pScan The scan object to use for configuration and for
* for storing the results.
* @param pCon The connection to use for output and errors.
* @param fEnd The end value for the diffscan
*/
int RunDiffScan(pDiffScan self, pScanData pScan,
SConnection *pCon, float fEnd);
/*==================== interpreter wrappers ==========================*/
int DiffScanWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int MakeDiffScan(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif

97
diffscan.w Normal file
View File

@ -0,0 +1,97 @@
\subsection{Differential Scan}
This is a special very fast but inaccurate scan method. The scan motor is
set into motion and counts are collected on the fly, while the motor
is moving. As neither the motor speed, nor the counters response nor
the source stability can be relied upon to result in equally spaced
and well defined counts, the counts have to be scaled according to the
difference in monitor counts towards the previous count. This is why
this is called differential scan. This is not a
precise scan. But is a very fast one which helps locating peaks or
during alignment.
This is implemented as an operator on top of the standard scan
module. All scan details, scan variables etc have to be configured in
the main scan module. This object then just runs the diff scan and
stores the result in the main scan object for further processing. For
instance peak location. The end of the scan is calculated from the
start, step and NP of the main scan module. be aware that these values
have no well defined meaning during this kind of scan, NP will be
corrected to account for the points actually measured.
As motors cannot be guaranteed to run simulataneously, only one scan
variable is suported for this.
The actual control of this scan is hidden in a task function which is
responsible for storing the data and stopping when the motor has
finished driving.
In order to do a differential scan a data structure is required:
@d diffscandat @{
typedef struct {
pObjectDescriptor pDes;
ObPar *parArray;
int normalizationScale;
int scaleMonitor;
CountEntry last;
int skip;
int skipCount;
pScanData scanObject;
} DiffScan, *pDiffScan;
@}
The fields:
\begin{description}
\item[pDes] The standard object descriptor.
\item[parArray] An array of parameters for the module.
\item[normalizationScale] The scale to which to scale counts during
counting.This will be the monitor difference between the first and the
second point.
\item[lastMonitor] is the last monitor read for caluclating differences.
\item[scaleMonitor] The monitor to use for scaling. This should better
be a monitor with a high count rate for acurate scaling.
\item[skip] How many cycles of the main loop to skip between
recordings.
\item[skipCount] Counter for skipped cycles. Together with skip this
is a means to limit the sampling rate of diffscan.
\item[scanObject] The scan object we are operating upon.
\end{description}
The external interface to this module is like this:
@d diffscanint @{
/**
* RunDiffScan runs a differential scan.
* @@param self The Diffscan object to use
* @@param pScan The scan object to use for configuration and for
* for storing the results.
* @@param pCon The connection to use for output and errors.
* @@param fEnd The end value for the diffscan
*/
int RunDiffScan(pDiffScan self, pScanData pScan,
SConnection *pCon, float fEnd);
/*==================== interpreter wrappers ==========================*/
int DiffScanWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int MakeDiffScan(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
@}
@o diffscan.h @{
/*-------------------------------------------------------------------
diffscan is an operator which can perform a fast differential scan
while a motor is running.
copyright: see file COPYRIGHT
Mark Koennecke, November 2004
---------------------------------------------------------------------*/
#ifndef SICSDIFFSCAN
#define SICSDIFFSCAN
#include "obpar.h"
#include "scan.h"
#include "scan.i"
@<diffscandat@>
/*==================================================================*/
@<diffscanint@>
#endif
@}

View File

@ -1,5 +1,5 @@
#line 88 "event.w"
#line 89 "event.w"
/*----------------------------------------------------------------------------
E V E N T
@ -18,7 +18,7 @@
int Text2Event(char *pText);
#line 101 "event.w"
#line 102 "event.w"
@ -43,7 +43,7 @@
#define BATCHEND 16
#define DRIVSTAT 17
#line 103 "event.w"
#line 104 "event.w"
/*--------------- Signals for the Signalfunction of each task ------------*/
@ -54,7 +54,8 @@
#define SICSBROADCAST 301
#define TOKENGRAB 302
#define TOKENRELEASE 303
#define COMLOG 304
#line 106 "event.w"
#line 107 "event.w"
#endif

View File

@ -105,6 +105,7 @@ $\langle$VSIG {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@#define SICSBROADCAST 301@\\
\mbox{}\verb@#define TOKENGRAB 302@\\
\mbox{}\verb@#define TOKENRELEASE 303@\\
\mbox{}\verb@#define COMLOG 304@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
@ -121,7 +122,7 @@ number which ocurred.
data is the string to send.
\item[TOKENGRAB] A connection has successfully grabbed the control token.
\item[TOKENRELEASE] A connection has released the control token.
\item[COMLOG] A command log message. This is to implement listen mode to the command log.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}

View File

@ -75,6 +75,7 @@ possible codes are defined.
#define SICSBROADCAST 301
#define TOKENGRAB 302
#define TOKENRELEASE 303
#define COMLOG 304
@}
\begin{description}
\item[SICSINT] An interrupt has ocurred. The signal data is the interrupt
@ -83,7 +84,7 @@ number which ocurred.
data is the string to send.
\item[TOKENGRAB] A connection has successfully grabbed the control token.
\item[TOKENRELEASE] A connection has released the control token.
\item[COMLOG] A command log message. This is to implement listen mode to the command log.
\end{description}
@o event.h -d @{
/*----------------------------------------------------------------------------

View File

@ -59,7 +59,9 @@ int exeBufAppend(pExeBuf self, char *line){
assert(self);
status = DynStringConcat(self->bufferContent,line);
DynStringConcatChar(self->bufferContent,'\n');
if(strrchr(line,(int)'\n') == NULL){
DynStringConcatChar(self->bufferContent,'\n');
}
return status;
}
/*-----------------------------------------------------------------------*/

View File

@ -169,6 +169,9 @@ static int runBatchBuffer(pExeMan self, SConnection *pCon,
pExeBuf buffer = NULL;
int status;
if(!SCMatchRights(pCon,usUser)) {
return 0;
}
filePath = locateBatchBuffer(self,name);
if(filePath == NULL){
snprintf(pBueffel,255,"ERROR: batch buffer %s not found in path",
@ -558,13 +561,24 @@ static int printBuffer(pExeMan self, SConnection *pCon,
int argc, char *argv[]){
pDynString filePath = NULL;
char pLine[512];
pExeBuf buf;
void *pPtr = NULL;
FILE *fd = NULL;
if(argc < 3){
SCWrite(pCon,"ERROR: argument required for exe print",eError);
return 0;
if(self->exeStackPtr >= 0) {
DynarGet(self->exeStack,self->exeStackPtr,&pPtr);
buf = (pExeBuf) pPtr;
if(buf != NULL){
filePath = locateBatchBuffer(self,exeBufName(buf));
}
} else {
SCWrite(pCon,"ERROR: no default buffer to print, argument required",eError);
return 0;
}
} else {
filePath = locateBatchBuffer(self,argv[2]);
}
filePath = locateBatchBuffer(self,argv[2]);
if(filePath == NULL){
snprintf(pLine,255,"ERROR: batch buffer %s not found in path",
argv[2]);
@ -610,7 +624,7 @@ static int enqueueBuffer(pExeMan self, SConnection *pCon,
buf = exeBufCreate("enqueue");
if(buf == NULL){
SCWrite(pCon,"ERROR: out of memory",eError);
return NULL;
return 0;
}
status = exeBufLoad(buf,GetCharArray(filePath));
DeleteDynString(filePath);
@ -727,9 +741,6 @@ int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
return status;
}else if(strcmp(argv[1],"info") == 0){
status = infoHandler(self,pCon,argc,argv);
if(status){
SCSendOK(pCon);
}
return status;
}else if(strcmp(argv[1],"print") == 0){
status = printBuffer(self,pCon,argc,argv);
@ -755,7 +766,11 @@ int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
}
return status;
} else {
return runBatchBuffer(self,pCon,pSics,pBufferName);
status = runBatchBuffer(self,pCon,pSics,pBufferName);
if(self->exeStackPtr < 0){
SCWrite(pCon,"EXE TERMINATED",eWarning);
}
return status;
}
} else {
SCWrite(pCon,"ERROR: need argument to manage batch buffers",eError);

View File

@ -488,12 +488,12 @@ static int *calculateSum(HistInt *data, int iDet, int iTime)
int i, j, iIndex;
int *sum = NULL;
sum = (int *)malloc(iDet*sizeof(int));
sum = (int *)malloc(iTime*sizeof(int));
if(!sum)
{
return NULL;
}
memset(sum,0,iDet*sizeof(int));
memset(sum,0,iTime*sizeof(int));
for(i = 0; i < iDet; i++)
{
@ -593,14 +593,14 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon,
/*
copy sum to make compiler happy
*/
lSum = (long *)malloc(iDet*sizeof(long));
lSum = (long *)malloc(iTime*sizeof(long));
if(lSum == NULL)
{
SCWrite(pCon,"ERROR: out of memory in putElastc",eError);
SCWrite(pCon,"ERROR: out of memory in putElastic",eError);
free(sum);
return NX_ERROR;
}
for(i = 0; i < iDet; i++)
for(i = 0; i < iTime; i++)
{
lSum[i] = sum[i];
}

View File

@ -555,6 +555,7 @@
{
return StringDictAddPair(self->pOption,name, value);
}
return 1;
}
/*-----------------------------------------------------------------------*/
int HistConfigure(pHistMem self, SConnection *pCon, SicsInterp *pSics)
@ -1055,6 +1056,8 @@ static int checkHMEnd(pHistMem self, char *text){
SCWrite(pCon,pBueffel,eError);
return 0;
}
SCSendOK(pCon);
return 1;
}
else if(strcmp(argv[1],"preset") == 0) /* preset */
{

View File

@ -49,9 +49,9 @@
#include "HistDriv.i"
#include "histsim.h"
/*
#define TESTVAL 128
/*
define TESTVAL to set the simulated histogram to a fixed value for
testing
@ -175,7 +175,7 @@
#ifdef TESTVAL
for(ii = iStart; ii < iEnd; ii++)
{
lData[ii] = TESTVAL;
lData[ii-iStart] = TESTVAL;
}
#else
if(iSet == 1)

14
hkl.c
View File

@ -1205,8 +1205,20 @@ ente:
return 1;
}
/*--------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
int GetHKLFromAngles(pHKL self, SConnection *pCon, float fHKL[3])
{
int status;
float fAng[4];
status = GetCurrentPosition(self,pCon,fAng);
if(status == 1)
{
angle2HKL(self,fAng[0], fAng[1], fAng[2], fAng[3],fHKL);
return 1;
}
return 0;
}
/*--------------------------------------------------------------------------*/
static int GetCommandData(int argc, char *argv[], float fHKL[3],
float *fPsi, int *iHamil, SConnection *pCon)

1
hkl.h
View File

@ -34,6 +34,7 @@
int GetLambda(pHKL self, float *fVal);
int GetCurrentHKL(pHKL self, float fVal[3]);
int GetCurrentPosition(pHKL self, SConnection *pCon, float fPosition[4]);
int GetHKLFromAngles(pHKL self, SConnection *pCon, float fVal[3]);
int CalculateSettings(pHKL self, float fHKL[3], float fPsi, int iHamil,
float fSet[4],SConnection *pCon);

2
hkl.i
View File

@ -25,6 +25,8 @@
pSelVar pMono;
long lID;
float scanTolerance;
float targetHKL[3];
int targetDirty;
} HKL;

86
hkl.tex
View File

@ -8,6 +8,9 @@ provided by Jean Allibon, ILL with the MAD four circle diffractometer
control program in ANSI-C. For theory, see the contribution by
W.C. Hamilton in the International Tables for Crystallography, 1974 edition.
There is a sister object to HKL which uses HKL to implement virtual motors for
H, K, and L. See below for the description
The object uses the following object data structure:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap1}
@ -33,6 +36,8 @@ $\langle$hkldat {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ pSelVar pMono;@\\
\mbox{}\verb@ long lID;@\\
\mbox{}\verb@ float scanTolerance;@\\
\mbox{}\verb@ float targetHKL[3];@\\
\mbox{}\verb@ int targetDirty;@\\
\mbox{}\verb@ } HKL;@\\
\mbox{}\verb@@$\diamond$
\end{list}
@ -65,6 +70,9 @@ checking.
\item[pMono] The selector variable doing the wavelength.
\item[scanTolerance] The hkl module refuses to position a reflection if it is
to close to omega limits for scanning. This is the tolerance to use.
\item[targetHKL] The target HKL values to support the H, K, L virtual motors
\item[targetDirty] A flag which is set when the virtual motors have to recalculate the
settings and to drive.
\end{description}
The wavelength is a bit tricky. As it would be to time consuming to read two
@ -102,6 +110,7 @@ $\langle$hklint {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int GetLambda(pHKL self, float *fVal);@\\
\mbox{}\verb@ int GetCurrentHKL(pHKL self, float fVal[3]);@\\
\mbox{}\verb@ int GetCurrentPosition(pHKL self, SConnection *pCon, float fPosition[4]);@\\
\mbox{}\verb@ int GetHKLFromAngles(pHKL self, SConnection *pCon, float fVal[3]); @\\
\mbox{}\verb@@\\
\mbox{}\verb@ int CalculateSettings(pHKL self, float fHKL[3], float fPsi, int iHamil,@\\
\mbox{}\verb@ float fSet[4],SConnection *pCon);@\\
@ -166,6 +175,7 @@ pointer to the connection object doing the command for error messages and
everything. The error returns are the same as with CalculateSettings
well. With the addition of HKJMOTFAIL, which means that a motor failed to
drive properly.
\item[GetHKLFromAngles] calculates the current HKL from Angles.
\item[DriveSettings] drives to the the settings given in fSet.
\item[HKLAction] is the interpreter wrapper function for the HKL object.
\end{description}
@ -220,3 +230,79 @@ drive properly.
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}
\subsubsection{The Crystallographic Virtual Motor Object}
This module implements virtual motors H, K and L on top of the HKL object. It was choosen to implement this
in a separate module because the hkl module is already big and complex enough. The problem is how to
keep track of the necessary settings for HKL because the motors are interrelated. This is solved in the
following scheme:
\begin{itemize}
\item Starting any of the motors H, K or L results in new values to be set in the HKL internal data
structure and a dirty flag to be set.
\item On a call to the drivable interfaces status function the dirty flag is checked and, if
appropriate, the motor positions are recalculated and the motors started.
\item H, K and L values are recalculated from motors on each read.
\end{itemize}
For each virtual motor an internal data structure is required:
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap5}
$\langle$hklmotdat {\footnotesize ?}$\rangle\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@typedef struct __HKLMOT {@\\
\mbox{}\verb@ pObjectDescriptor pDes;@\\
\mbox{}\verb@ pHKL pHkl;@\\
\mbox{}\verb@ pIDrivable pDriv;@\\
\mbox{}\verb@ int index;@\\
\mbox{}\verb@ }HKLMot, *pHKLMot;@\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
\item Macro referenced in scrap ?.
\end{list}
\end{minipage}\\[4ex]
\end{flushleft}
The fields are:\begin{description}
\item[pDes] The required object descriptor.
\item[pHkl] The HKL object to use for calculations.
\item[pDriv] The drivable interface.
\item[index] The index of the motors target in the targetHKL array in the HKL structure.
\end{description}
The target HKL and the dirty flag is in the main HKL data structure.
There is no external interface to this, all the functionality is hidden in the drivable interface
functions. The interpreter interface is minimal: only a value request is supported. There is
however a factory function in order to install the HKL motors into the interpreter.
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap6}
\verb@"hklmot.h"@ {\footnotesize ? }$\equiv$
\vspace{-1ex}
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@/*------------------------------------------------------------------------------------------------------@\\
\mbox{}\verb@ Virtual motor interface to reciprocal space coordinates H, K and L for a four circle diffractometer.@\\
\mbox{}\verb@ Requires a HKL object for calculations.@\\
\mbox{}\verb@@\\
\mbox{}\verb@ copyright: see file COPYRIGHT@\\
\mbox{}\verb@@\\
\mbox{}\verb@ Mark Koennecke, February 2005@\\
\mbox{}\verb@--------------------------------------------------------------------------------------------------------*/@\\
\mbox{}\verb@#ifndef SICSHKLMOT@\\
\mbox{}\verb@#define SICSHKLMOT@\\
\mbox{}\verb@/*====================== data structure ==============================================================*/@\\
\mbox{}\verb@@$\langle$hklmotdat {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@/*======================= interpreter interface ======================================================*/@\\
\mbox{}\verb@int HKLMotAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]);@\\
\mbox{}\verb@int HKLMotInstall(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]);@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@\\
\mbox{}\verb@ @\\
\mbox{}\verb@@$\diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
\end{flushleft}

65
hkl.w
View File

@ -8,6 +8,9 @@ provided by Jean Allibon, ILL with the MAD four circle diffractometer
control program in ANSI-C. For theory, see the contribution by
W.C. Hamilton in the International Tables for Crystallography, 1974 edition.
There is a sister object to HKL which uses HKL to implement virtual motors for
H, K, and L. See below for the description
The object uses the following object data structure:
@d hkldat @{
typedef struct __HKL {
@ -28,6 +31,8 @@ The object uses the following object data structure:
pSelVar pMono;
long lID;
float scanTolerance;
float targetHKL[3];
int targetDirty;
} HKL;
@}
@ -53,6 +58,9 @@ checking.
\item[pMono] The selector variable doing the wavelength.
\item[scanTolerance] The hkl module refuses to position a reflection if it is
to close to omega limits for scanning. This is the tolerance to use.
\item[targetHKL] The target HKL values to support the H, K, L virtual motors
\item[targetDirty] A flag which is set when the virtual motors have to recalculate the
settings and to drive.
\end{description}
The wavelength is a bit tricky. As it would be to time consuming to read two
@ -85,6 +93,7 @@ module:
int GetLambda(pHKL self, float *fVal);
int GetCurrentHKL(pHKL self, float fVal[3]);
int GetCurrentPosition(pHKL self, SConnection *pCon, float fPosition[4]);
int GetHKLFromAngles(pHKL self, SConnection *pCon, float fVal[3]);
int CalculateSettings(pHKL self, float fHKL[3], float fPsi, int iHamil,
float fSet[4],SConnection *pCon);
@ -141,6 +150,7 @@ pointer to the connection object doing the command for error messages and
everything. The error returns are the same as with CalculateSettings
well. With the addition of HKJMOTFAIL, which means that a motor failed to
drive properly.
\item[GetHKLFromAngles] calculates the current HKL from Angles.
\item[DriveSettings] drives to the the settings given in fSet.
\item[HKLAction] is the interpreter wrapper function for the HKL object.
\end{description}
@ -178,3 +188,58 @@ drive properly.
@<hklint@>
#endif
@}
\subsubsection{The Crystallographic Virtual Motor Object}
This module implements virtual motors H, K and L on top of the HKL object. It was choosen to implement this
in a separate module because the hkl module is already big and complex enough. The problem is how to
keep track of the necessary settings for HKL because the motors are interrelated. This is solved in the
following scheme:
\begin{itemize}
\item Starting any of the motors H, K or L results in new values to be set in the HKL internal data
structure and a dirty flag to be set.
\item On a call to the drivable interfaces status function the dirty flag is checked and, if
appropriate, the motor positions are recalculated and the motors started.
\item H, K and L values are recalculated from motors on each read.
\end{itemize}
For each virtual motor an internal data structure is required:
@d hklmotdat @{
typedef struct __HKLMOT {
pObjectDescriptor pDes;
pHKL pHkl;
pIDrivable pDriv;
int index;
}HKLMot, *pHKLMot;
@}
The fields are:\begin{description}
\item[pDes] The required object descriptor.
\item[pHkl] The HKL object to use for calculations.
\item[pDriv] The drivable interface.
\item[index] The index of the motors target in the targetHKL array in the HKL structure.
\end{description}
The target HKL and the dirty flag is in the main HKL data structure.
There is no external interface to this, all the functionality is hidden in the drivable interface
functions. The interpreter interface is minimal: only a value request is supported. There is
however a factory function in order to install the HKL motors into the interpreter.
@o hklmot.h @{
/*------------------------------------------------------------------------------------------------------
Virtual motor interface to reciprocal space coordinates H, K and L for a four circle diffractometer.
Requires a HKL object for calculations.
copyright: see file COPYRIGHT
Mark Koennecke, February 2005
--------------------------------------------------------------------------------------------------------*/
#ifndef SICSHKLMOT
#define SICSHKLMOT
/*====================== data structure ==============================================================*/
@<hklmotdat@>
/*======================= interpreter interface ======================================================*/
int HKLMotAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]);
int HKLMotInstall(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]);
#endif
@}

247
hklmot.c Normal file
View File

@ -0,0 +1,247 @@
/*------------------------------------------------------------------------------------------------------
Virtual motor interface to reciprocal space coordinates H, K and L for a four circle diffractometer.
Requires a HKL object for calculations.
copyright: see file COPYRIGHT
Mark Koennecke, February 2005
--------------------------------------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include "sics.h"
#include "fortify.h"
#include "motor.h"
#include "matrix/matrix.h"
#include "hkl.h"
#include "hkl.i"
#include "hklmot.h"
/*=================== Object Descriptor Interface ===================================================*/
static void *HKLGetInterface(void *pData, int iID){
pHKLMot self = NULL;
self = (pHKLMot)pData;
if(self == NULL){
return NULL;
}
if(iID == DRIVEID){
return self->pDriv;
}
return NULL;
}
/*=================== Drivable Interface ============================================================*/
static int HKLHalt(void *pData){
pHKLMot self = NULL;
self = (pHKLMot)pData;
assert(self != NULL);
self->pHkl->pTheta->pDrivInt->Halt(self->pHkl->pTheta);
self->pHkl->pOmega->pDrivInt->Halt(self->pHkl->pOmega);
if(self->pHkl->iNOR == 1){
self->pHkl->pNu->pDrivInt->Halt(self->pHkl->pNu);
} else {
self->pHkl->pChi->pDrivInt->Halt(self->pHkl->pChi);
self->pHkl->pPhi->pDrivInt->Halt(self->pHkl->pPhi);
}
return 1;
}
/*-----------------------------------------------------------------------------------------------------*/
static int HKLCheckLimits(void *self, float fVal, char *error, int errLen){
/*
There is no meaningful implementation here. This gets called when starting the motor.
At that stage not all other values may be known. If the calculation failes, this will die
at status check time.
*/
return 1;
}
/*----------------------------------------------------------------------------------------------------*/
static long HKLSetValue(void *pData, SConnection *pCon, float fVal){
pHKLMot self = NULL;
if(!SCMatchRights(pCon,usUser)){
return 0;
}
self = (pHKLMot)pData;
assert(self != NULL);
self->pHkl->targetHKL[self->index] = fVal;
self->pHkl->targetDirty = 1;
return OKOK;
}
/*---------------------------------------------------------------------------------------------------*/
static int checkMotors(pHKLMot self, SConnection *pCon){
int status;
status = self->pHkl->pTheta->pDrivInt->CheckStatus(self->pHkl->pTheta, pCon);
if(status != HWIdle && status != OKOK){
return status;
}
status = self->pHkl->pOmega->pDrivInt->CheckStatus(self->pHkl->pOmega, pCon);
if(status != HWIdle && status != OKOK){
return status;
}
if(self->pHkl->iNOR == 1){
status = self->pHkl->pNu->pDrivInt->CheckStatus(self->pHkl->pNu, pCon);
if(status != HWIdle && status != OKOK){
return status;
}
} else {
status = self->pHkl->pChi->pDrivInt->CheckStatus(self->pHkl->pChi, pCon);
if(status != HWIdle && status != OKOK){
return status;
}
status = self->pHkl->pPhi->pDrivInt->CheckStatus(self->pHkl->pPhi, pCon);
if(status != HWIdle && status != OKOK){
return status;
}
}
return HWIdle;
}
/*-----------------------------------------------------------------------------------------------------*/
static int HKLCheckStatus(void *pData, SConnection *pCon){
pHKLMot self = NULL;
int status;
self = (pHKLMot)pData;
assert(self != NULL);
if(self->pHkl->targetDirty == 1){
status = RunHKL(self->pHkl,self->pHkl->targetHKL,.0,0,pCon);
if(status != 1){
return HWFault;
}
self->pHkl->targetDirty = 0;
return HWBusy;
} else {
return checkMotors(self,pCon);
}
}
/*-----------------------------------------------------------------------------------------------------*/
static float HKLGetValue(void *pData, SConnection *pCon){
pHKLMot self = NULL;
float fVal[3];
int status;
self = (pHKLMot)pData;
assert(self != NULL);
status = GetHKLFromAngles(self->pHkl,pCon,fVal);
if(status != 1){
SCWrite(pCon,"ERROR: failed to read positions or convert to HKL",eError);
return -9999.99;
}
return fVal[self->index];
}
/*=============================== Live and Death ====================================*/
static pHKLMot MakeHKLMot(pHKL pHkl, int index){
pHKLMot self = NULL;
assert(pHkl != NULL);
assert(index >= 0 && index < 3);
self = (pHKLMot)malloc(sizeof(HKLMot));
if(self == NULL){
return NULL;
}
memset(self,0,sizeof(HKLMot));
self->pDes = CreateDescriptor("HKLMot");
self->pDriv = CreateDrivableInterface();
if(self->pDes == NULL || self->pDriv == NULL){
free(self);
return NULL;
}
self->pDes->GetInterface = HKLGetInterface;
self->pDriv->Halt = HKLHalt;
self->pDriv->CheckLimits = HKLCheckLimits;
self->pDriv->SetValue = HKLSetValue;
self->pDriv->CheckStatus = HKLCheckStatus;
self->pDriv->GetValue = HKLGetValue;
self->pHkl = pHkl;
self->index = index;
return self;
}
/*----------------------------------------------------------------------------------*/
static void KillHklMot(void *pData){
pHKLMot self = NULL;
self = (pHKLMot)pData;
if(self == NULL){
return;
}
if(self->pDes != NULL){
DeleteDescriptor(self->pDes);
}
if(self->pDriv){
free(self->pDriv);
}
free(self);
}
/*=============================== Interpreter Interface ============================*/
int HKLMotAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){
pHKLMot self = NULL;
float value;
char pBuffer[132];
self = (pHKLMot)pData;
assert(self != NULL);
value = self->pDriv->GetValue(self,pCon);
if(value < -9000.){
snprintf(pBuffer,131,"ERROR: failed to read %s",argv[0]);
SCWrite(pCon,pBuffer,eError);
return 0;
}
snprintf(pBuffer,131,"%s = %f", argv[0], value);
SCWrite(pCon,pBuffer,eValue);
return 1;
}
/*------------------------------------------------------------------------------------------*/
int HKLMotInstall(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){
pHKL pHkl;
pHKLMot pMot = NULL;
char pBuffer[131];
if(argc < 2){
SCWrite(pCon,"ERROR: Insifficient number of arguments to HKLMotInstall",eError);
return 0;
}
strtolower(argv[1]);
pHkl = (pHKL)FindCommandData(pSics,argv[1],"4-Circle-Calculus");
if(pHkl == NULL){
snprintf(pBuffer,131,"ERROR: %s is not present or no HKL object",argv[1]);
SCWrite(pCon,pBuffer,eError);
return 0;
}
pMot = MakeHKLMot(pHkl, 0);
if(pMot == NULL){
SCWrite(pCon,"ERROR: out of memory creating H Motor",eError);
return 0;
}
if(!AddCommand(pSics,"H",HKLMotAction,KillHklMot,pMot)){
SCWrite(pCon,"ERROR: duplicate command H not created",eError);
return 0;
}
pMot = MakeHKLMot(pHkl, 1);
if(pMot == NULL){
SCWrite(pCon,"ERROR: out of memory creating K Motor",eError);
return 0;
}
if(!AddCommand(pSics,"K",HKLMotAction,KillHklMot,pMot)){
SCWrite(pCon,"ERROR: duplicate command K not created",eError);
return 0;
}
pMot = MakeHKLMot(pHkl, 2);
if(pMot == NULL){
SCWrite(pCon,"ERROR: out of memory creating L Motor",eError);
return 0;
}
if(!AddCommand(pSics,"L",HKLMotAction,KillHklMot,pMot)){
SCWrite(pCon,"ERROR: duplicate command L not created",eError);
return 0;
}
return 1;
}

27
hklmot.h Normal file
View File

@ -0,0 +1,27 @@
/*------------------------------------------------------------------------------------------------------
Virtual motor interface to reciprocal space coordinates H, K and L for a four circle diffractometer.
Requires a HKL object for calculations.
copyright: see file COPYRIGHT
Mark Koennecke, February 2005
--------------------------------------------------------------------------------------------------------*/
#ifndef SICSHKLMOT
#define SICSHKLMOT
/*====================== data structure ==============================================================*/
typedef struct __HKLMOT {
pObjectDescriptor pDes;
pHKL pHkl;
pIDrivable pDriv;
int index;
}HKLMot, *pHKLMot;
/*======================= interpreter interface ======================================================*/
int HKLMotAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]);
int HKLMotInstall(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]);
#endif

16
macro.c
View File

@ -129,7 +129,7 @@
SConnection *pCon = NULL;
CommandList *pCommand = NULL;
char *lastCommand = NULL, comBuffer[132];
int iRet,i;
int iRet = 0,i;
int iMacro;
/* get the datastructures */
@ -194,7 +194,7 @@
}
/* finish */
if(iRet)
if(iRet == 1)
{
return TCL_OK;
}
@ -328,6 +328,10 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp,
Tcl_DeleteCommand(pInter,"socket");
Tcl_DeleteCommand(pInter,"vwait");
Tcl_DeleteCommand(pInter,"exec");
/*
install protected exec command
*/
Tcl_CreateObjCommand(pInter,"exec",ProtectedExec,NULL,KillExec);
return pInter;
@ -847,8 +851,9 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp,
iRet = Tcl_Eval(pTcl,pBueffel);
if(iRet == TCL_OK)
{ /* possibly a bug here */
SCWrite(pCon,pTcl->result,eStatus);
{
strncpy(pBueffel,pTcl->result,1023);
SCWrite(pCon,pBueffel,eStatus);
return 1;
}
else
@ -862,7 +867,8 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp,
else
{
Tcl_UnsetVar(pTcl,SICSERROR,TCL_GLOBAL_ONLY);
SCWrite(pCon,pTcl->result,eError);
strncpy(pBueffel,pTcl->result,1023);
SCWrite(pCon,pBueffel,eError);
}
return 0;
}

View File

@ -19,7 +19,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
histmem.o histdriv.o histsim.o interface.o callback.o \
event.o emon.o evcontroller.o evdriver.o simev.o perfmon.o \
danu.o nxdict.o varlog.o stptok.o nread.o \
scan.o fitcenter.o telnet.o token.o wwildcard.o\
scan.o fitcenter.o telnet.o token.o wwildcard.o hklmot.o\
tclev.o hkl.o integrate.o optimise.o dynstring.o nxutil.o \
mesure.o uubuffer.o commandlog.o udpquieck.o \
rmtrail.o help.o nxupdate.o confvirtualmot.o \

View File

@ -169,7 +169,7 @@ CreateSocketAdress(
assert(self != NULL);
if(timeout > 0)
if(timeout >= 0)
{
/* select first */
tmo.tv_usec = (timeout % 1000) * 1000;
@ -256,13 +256,15 @@ CreateSocketAdress(
free(pRes);
return NULL;
}
/*
i = sizeof(struct linger);
lili.l_onoff = 1;
lili.l_linger = 1;
/* setsockopt(pRes->sockid,SOL_SOCKET,SO_LINGER,&lili,i);
setsockopt(pRes->sockid,SOL_SOCKET,SO_LINGER,&lili,i);
i = 1;
setsockopt(pRes->sockid,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int));
*/ pRes->iType = SOCKET;
*/
pRes->iType = SOCKET;
pRes->lMagic = NETMAGIC;
return pRes;
}
@ -386,7 +388,7 @@ CreateSocketAdress(
return 0;
}
if(timeout > 0)
if(timeout >= 0)
{
/* setup for select first */
tmo.tv_usec = (timeout % 1000) *1000;
@ -739,7 +741,7 @@ This old version may be removed in some stage. It has two problems:
}
assert(self->iType == UDP);
if(timeout > 0)
if(timeout >= 0)
{
/* setup for select first */
tmo.tv_usec = (timeout % 1000) *1000;

View File

@ -86,7 +86,7 @@ extern VerifyChannel(mkChannel *self); /* defined in network.c */
assert(pTask);
assert(iPasswdTimeout > 0);
assert(iReadTimeout > 0);
assert(iReadTimeout >= 0);
pNew = (pNetRead)malloc(sizeof(NetReader));
if(!pNew)

View File

@ -160,7 +160,7 @@ static int handleFileOperations(SConnection *pCon, pNXScript self,
if(argc < 4){
SCWrite(pCon,"ERROR: insufficient number of arguments for file operation",
eError);
return 1;
return -1;
}
/*
be considerate: close files left open
@ -180,11 +180,13 @@ static int handleFileOperations(SConnection *pCon, pNXScript self,
if(status != NX_OK){
sprintf(buffer,"ERROR: failed to open %s",argv[2]);
SCWrite(pCon,buffer,eError);
return -1;
}
status = NXDinitfromfile(argv[3],&self->dictHandle);
if(status != NX_OK){
sprintf(buffer,"ERROR: failed to open dictionary %s",argv[3]);
SCWrite(pCon,buffer,eError);
return -1;
}
SCSendOK(pCon);
return 1;
@ -261,6 +263,7 @@ static void putCounter(SConnection *pCon, SicsInterp *pSics, pNXScript self,
eError);
return;
}
memset(dummy,0,80*sizeof(char));
/*
find counter
@ -897,6 +900,8 @@ int NXScriptAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pNXScript self = (pNXScript)pData;
char *pFile = NULL;
int status;
/*
preliminary checks
*/
@ -934,7 +939,10 @@ int NXScriptAction(SConnection *pCon, SicsInterp *pSics, void *pData,
if(handleFileOperations(pCon,self,argc,argv)){
status = handleFileOperations(pCon,self,argc,argv);
if(status < 0){
return 0;
} else if(status == 1){
return 1;
}

4
ofac.c
View File

@ -108,6 +108,7 @@
#include "exeman.h"
#include "oscillate.h"
#include "diffscan.h"
#include "hklmot.h"
/*----------------------- Server options creation -------------------------*/
static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
@ -291,6 +292,8 @@
MakeOscillator,NULL,NULL);
AddCommand(pInter,"MakeDiffScan",
MakeDiffScan,NULL,NULL);
AddCommand(pInter,"MakeHKLMot",
HKLMotInstall,NULL,NULL);
/*
@ -352,6 +355,7 @@
RemoveCommand(pSics,"MakeBatchManager");
RemoveCommand(pSics,"MakeOscillator");
RemoveCommand(pSics,"MakeDiffScan");
RemoveCommand(pSics,"MakeHKLMot");
/*
remove site specific installation commands

View File

@ -134,6 +134,10 @@ int writeRS232(prs232 self, void *data, int dataLen)
if(pPtr != NULL)
free(pPtr);
if(iRet != 1){
return BADSEND;
}
return iRet;
}
/*----------------------------------------------------------------------*/
@ -213,17 +217,21 @@ int readRS232TillTerm(prs232 self, void *data, int *datalen){
replylen = *datalen;
iRet = NETReadTillTermNew(self->pSock,self->timeout,self->replyTerminator,
(char *)data, replylen);
if(self->debug > 0)
if(self->debug > 0 && iRet == 1)
{
printf("RS232 IN/TERM : %s",(char *)data);
if(strchr((char *)data,'\n') == NULL)
{
puts("");
puts("");
}
fflush(stdout);
}
if(iRet == 0)
{
if(self->debug > 0)
{
printf("RS232 IN/TERM : TIMEOUT:%s\n",(char *)data);
}
return TIMEOUT;
}
else if(iRet == -1)
@ -307,9 +315,9 @@ int transactRS232(prs232 self, void *send, int sendLen,
write data
*/
iRet = writeRS232(self,send,sendLen);
if(iRet < 0)
if(iRet <= 0)
{
return iRet;
return BADSEND;
}
/*
@ -320,12 +328,23 @@ int transactRS232(prs232 self, void *send, int sendLen,
reply, replyLen);
if(self->debug > 0)
{
printf("RS232 IN/TRANS: %s",(char *)reply);
if(strchr((char *)reply,'\n') == NULL)
if(iRet == 1)
{
puts("");
printf("RS232 IN/TRANS: %s",(char *)reply);
if(strchr((char *)reply,'\n') == NULL)
{
puts("");
}
fflush(stdout);
}
else if(iRet == 0)
{
printf("RS232 IN/TRANS: TIMEOUT\n");
}
else
{
printf("RS232 IN/TRANS/INCOMPLETE: %s",(char *)reply);
}
fflush(stdout);
}
if(iRet == 0)
{
@ -362,7 +381,7 @@ void getRS232Error(int iCode, char *errorBuffer,
break;
case TIMEOUT:
strncpy(errorBuffer,
"Timeout reading data",
"Timeout or network error when reading data",
errorBufferLen);
break;
case FAILEDCONNECT:
@ -374,6 +393,9 @@ void getRS232Error(int iCode, char *errorBuffer,
strncpy(errorBuffer,"Did not find terminator in read buffer",
errorBufferLen);
break;
case BADSEND:
strncpy(errorBuffer,"Network problem: failed to send",errorBufferLen);
break;
default:
strncpy(errorBuffer,strerror(errno),
errorBufferLen);
@ -407,6 +429,21 @@ int initRS232(prs232 self)
return 1;
}
}
/*--------------------------------------------------------------------*/
void closeRS232(prs232 self)
{
assert(self);
if(self->pSock != NULL)
{
if(pServ->pReader != NULL){
NetReadRemoveUserSocket(pServ->pReader,self->pSock->sockid);
}
NETClosePort(self->pSock);
free(self->pSock);
self->pSock = NULL;
}
}
/*------------------------------------------------------------------*/
prs232 createRS232(char *host, int iPort)
{

View File

@ -22,6 +22,8 @@
#define TIMEOUT -2702
#define FAILEDCONNECT -2703
#define INCOMPLETE -2704
#define BADREAD -2705
#define BADSEND -2706
/*----------------------- a data structure ----------------------------*/
@ -63,6 +65,7 @@
int errorBufferLen);
int initRS232(prs232 self);
void closeRS232(prs232 self);
prs232 createRS232(char *host, int iPort);
void KillRS232(void *pData);

View File

@ -69,6 +69,7 @@ The following interface functions are provided:
int errorBufferLen);
int initRS232(prs232 self);
void closeRS232(prs232 self);
prs232 createRS232(char *host, int iPort);
void KillRS232(void *pData);
@}
@ -102,6 +103,7 @@ directly followed by a read.
iCode.
\item[initRS232] tries to close and reopen the RS232 connection. This is
useful for the automatic fixing of communication problems encountered.
\item[closeRS232] closes a network connection but does not delete the datastructure.
\item[createRS232] creates a new rs232 data structure with all
parameters at default values. The connection is NOT opened.
\end{description}
@ -130,6 +132,8 @@ parameters at default values. The connection is NOT opened.
#define TIMEOUT -2702
#define FAILEDCONNECT -2703
#define INCOMPLETE -2704
#define BADREAD -2705
#define BADSEND -2706
/*----------------------- a data structure ----------------------------*/
@<rs232dat@>

158
sans2.tcl
View File

@ -1,33 +1,48 @@
# --------------------------------------------------------------------------
# Initialization script for the instrument SANSII at SINQ
#
# Dr. Mark Koennecke, January - ???? 2003
# Dr. Mark Koennecke, January - March 2003
#
# Changes:
# Pavel Strunz, 15.04.2003: - changed backlash dz (0.15 --> 0.005)
# Pavel Strunz, 16.04.2003: - changed NVS forbiden gaps according to the actual NVS037
# Pavel Strunz, 23.04.2003: - changed backlash for all ecb motors
# Pavel Strunz, 29.04.2003: - hakle.tcl sourced
# Pavel Strunz, 20.11.2003: - source sans2geometry, sans2measurement
# Pavel Strunz, 03.12.2003: - source scan_a, sans2wavelength, nvs interrupt changed from 3 to 0
#---------------------------------------------------------------------------
# O P T I O N S
set root "/afs/psi.ch/user/k/koennecke/src/sics"
set root "/home/SANS2"
set scriptroot $root/sans2_sics
# first all the server options are set
ServerOption SaveFile $root/tmp/sans2stat.tcl
ServerOption statusfile $root/data/2003/sans2stat.tcl
# File to save the status of the instrument too
ServerOption ReadTimeOut 10
ServerOption ReadTimeOut 5
# 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
ServerOption AcceptTimeOut 5
# 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
# time to wait 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 $root/tmp/sans2log
ServerOption LogFileBaseName $root/log/sans2log
# the path and base name of the internal server logfile to which all
# activity will be logged.
ServerOption ServerPort 2915
ServerOption LogFileDir $root/log
# This is where log files from command log go
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
@ -46,9 +61,11 @@ TokenInit connan
# than the SICS users are specified
# Syntax: SicsUser name password userRightsCode
SicsUser Manager Joachim 1
SicsUser User Kohl 2
SicsUser Spy 007 1
SicsUser Manager Manager 1
SicsUser lnsmanager lnsSICSlns 1
SicsUser User Looser 2
SicsUser sans2user 04lns1 2
SicsUser Spy 007 3
#--------------------------------------------------------------------------
# S I M P L E V A R I A B L E S
@ -68,7 +85,7 @@ VarMake User Text User
VarMake SubTitle Text User
VarMake environment Text User
VarMake comment Text User
VarMake samplename Text User
#VarMake samplename Text User
VarMake email Text User
VarMake fax Text User
VarMake phone Text User
@ -77,20 +94,21 @@ VarMake sample Text User
VarMake BatchRoot Text User
VarMake starttime Text User
BatchRoot $root
#BatchRoot $root/command
VarMake sampletable Text User
#----------- Initialize data storage stuff
VarMake SicsDataPath Text Mugger
SicsDataPath $root/tmp/
SicsDataPath $root/data/2004/
SicsDataPath lock
VarMake SicsDataPrefix Text Mugger
SicsDataPrefix sansII
SicsDataPrefix sans2
SicsDataPrefix lock
VarMake SicsDataPostFix Text Mugger
SicsDataPostFix ".hdf"
SicsDataPostFix lock
MakeDataNumber SicsDataNumber $root/tmp/DataNumber
MakeDataNumber SicsDataNumber $root/data/2004/DataNumber
#=========================================================================
# Initialize ECB system
@ -113,7 +131,7 @@ ecbauto
#-------------- ECB Motors
# Motor name ecb ecb-controller ecb-motor-index hardlowerlimit hardupperlimit
Motor sr ecb ecb1 1 -10000. 10000.
Motor sr ecb ecb1 1 -17500. 17500.
sr encoder 0
sr control 0
sr range 1
@ -130,7 +148,7 @@ sr offset 0
sr dtolerance .01
sr step2deg 1
sr step2dig 0
sr backlash .15
sr backlash 500
Motor stx ecb ecb1 2 -16000. 16000.
stx encoder 0
@ -149,7 +167,7 @@ stx offset 0
stx dtolerance .01
stx step2deg 1
stx step2dig 0
stx backlash .15
stx backlash 500
Motor stz ecb ecb1 3 6500. 20000.
stz encoder 0
@ -168,7 +186,7 @@ stz offset 0
stz dtolerance .01
stz step2deg 1
stz step2dig 0
stz backlash .15
stz backlash 500
Motor sc ecb ecb1 4 -2000. 70000.
sc encoder 0
@ -187,7 +205,7 @@ sc offset 0
sc dtolerance .01
sc step2deg 1
sc step2dig 0
sc backlash .15
sc backlash 1000
Motor gu ecb ecb1 5 -10000. 10000.
gu encoder 0
@ -206,7 +224,7 @@ gu offset 0
gu dtolerance .02
gu step2deg 1
gu step2dig 0
gu backlash .15
gu backlash 100
Motor gl ecb ecb1 6 -10000. 10000.
gl encoder 0
@ -225,7 +243,7 @@ gl offset 0
gl dtolerance .02
gl step2deg 1
gl step2dig 0
gl backlash .15
gl backlash 100
Motor tu ecb ecb1 7 -10000. 10000.
@ -245,7 +263,7 @@ tu offset 0
tu dtolerance .01
tu step2deg 1
tu step2dig 0
tu backlash .15
tu backlash 100
Motor tl ecb ecb1 8 -10000. 10000.
@ -265,7 +283,7 @@ tl offset 0
tl dtolerance .01
tl step2deg 1
tl step2dig 0
tl backlash .15
tl backlash 100
Motor om ecb ecb1 9 -10000. 10000.
om encoder 1
@ -284,7 +302,7 @@ om offset 0
om dtolerance .01
om step2deg 1
om step2dig 10
om backlash .15
om backlash 100
Motor sz ecb ecb1 10 -10000. 10000.
sz encoder 0
@ -303,7 +321,7 @@ sz offset 0
sz dtolerance .001
sz step2deg 1
sz step2dig 0
sz backlash .15
sz backlash 100
Motor sx ecb ecb1 11 -10000. 10000.
sx encoder 0
@ -322,7 +340,7 @@ sx offset 0
sx dtolerance .01
sx step2deg 1
sx step2dig 0
sx backlash .15
sx backlash 100
Motor sy ecb ecb1 12 -10000. 10000.
sy encoder 0
@ -341,9 +359,9 @@ sy offset 0
sy dtolerance .001
sy step2deg 1
sy step2dig 0
sy backlash .15
sy backlash 100
Motor dz ecb ecb1 13 1.05 6.0
Motor dz ecb ecb1 13 0.905 6.015
dz encoder 0
dz control 0
dz range 1
@ -360,9 +378,9 @@ dz offset 0
dz dtolerance .001
dz step2deg 53076
dz step2dig 0
dz backlash .15
dz backlash .005
Motor dh ecb ecb1 14 -14000. 16000.
Motor dh ecb ecb1 14 -10100. 16400.
dh encoder 0
dh control 0
dh range 1
@ -379,9 +397,9 @@ dh offset 0
dh dtolerance .001
dh step2deg 1
dh step2dig 0
dh backlash .15
dh backlash 100
Motor dv ecb ecb1 15 -14000. 25000.
Motor dv ecb ecb1 15 -14600. 25400.
dv encoder 0
dv control 0
dv range 1
@ -398,7 +416,7 @@ dv offset 0
dv dtolerance .001
dv step2deg 1
dv step2dig 0
dv backlash .15
dv backlash 100
Motor az1 ecb ecb1 16 -3900. 0.
az1 encoder 0
@ -417,7 +435,7 @@ az1 offset 0
az1 dtolerance .001
az1 step2deg 1
az1 step2dig 0
az1 backlash .15
az1 backlash 200
Motor atz ecb ecb1 17 -3900. 0.
atz encoder 0
@ -436,7 +454,7 @@ atz offset 0
atz dtolerance .001
atz step2deg 1
atz step2dig 0
atz backlash .15
atz backlash 200
#===========================================================================
# The ECB system has the drawback that only one out of 8 motors in a rack
@ -531,12 +549,16 @@ proc sans2rack args {
}
return
}
Publish sans2rack User #---------for testing purposes
Publish sans2rack User
anticollision script sans2rack
#====================== PSI Motoren ===================================
Motor ome EL734 sans2 4000 2 1
Motor chi EL734 sans2 4000 2 2
Motor tilt EL734 sans2 4000 3 1
Motor ome EL734 sans2 4000 3 1
Motor chi EL734 sans2 4000 3 2
Motor phi EL734 sans2 4000 3 3
Motor tilt EL734 sans2 4000 2 1
SicsAlias ome traz "These motors are used to drive SANS I translation table"
SicsAlias chi trax "while ome is sample z and chi is sample x (TG070704)"
#====================== Multi Motor Setup ==============================
MakeMulti detector
detector alias dz x
@ -565,9 +587,9 @@ gonio endconfig
MakeMulti table
table alias om om
table alias sz z
table alias sx x
table alias sx x
table alias sy y
table endconfig
table endconfig#
#====================== HISTOGRAM MEMORY ================================
MakeCounter counter ecb ecb1
MakeECB tdc gpib 0 7
@ -587,27 +609,57 @@ banana init
banana exponent 6
banana CountMode timer
banana preset 100
#=========================== velocity selector ========================
VelocitySelector nvs tilt SIM
=========================== velocity selector ========================
set dorn(Host) psts233
set dorn(Port) 3004
set dorn(Channel) 4
set dorn(Timeout) 20000
set dorn(MinControl) 6500
VelocitySelector nvs tilt dornier2003 dorn
#VelocitySelector nvs tilt SIM
nvs add -20 28800
nvs add 3600 4300
nvs add 7600 9600
nvs add 13400 13450
nvs add 24200 24250
nvs add 3600 4500
nvs add 7800 10500
nvs add 21500 23500
nvs status
nvs interrupt 0
MakeSANSWave lambda nvs
emon unregister nvswatch
#===================================== auxiliary hardware ==============
set distoCON [gpib attach 0 14 0 13 0 1]
#--------- for the Hakle Feucht
MakeRS232Controller h50 psts233 3005
#===================================== data file writing ================
MakeNXScript
#===================================== install commands ==================
MakeDrive
MakeRuenBuffer
commandlog auto
#=================================== load specific command file ===========
source $root/sans2com.tcl
MakePSDFrame
SerialInit
#--------- drive command
MakeDrive
SicsAlias drive dr
#----------- for adding scripted content to the status file
MakeTclInt bckintern
#----- alias for temperature
DefineAlias tt temperature
#=================================== load specific command files ===========
source $scriptroot/sans2com.tcl
source $scriptroot/hakle.tcl
source $scriptroot/hakle50.tcl
source $scriptroot/HaakeSetup.tcl
source $scriptroot/A1931Setup.tcl
source $scriptroot/sans2geometry.tcl
source $scriptroot/sans2measurement.tcl
source $scriptroot/sans2wavelength.tcl
source $scriptroot/scan_a.tcl
# initialisation for IPS-120 superconducting magnet power supply
# this definition does not harm other devices used through the same channel
ips init localhost 4000 7
#=================================== load display definition =============
source $root/sans2dis.tcl
#source $scriptroot/sans2dis.tcl
#=======================================================================
disto

View File

@ -40,7 +40,7 @@
*name, float start, float step);
/**
* InitScanVar clears the list of scan points
* @param pvar The scna variable to clear
* @param pvar The scan variable to clear
*/
void InitScanVar(pVarEntry pVar);
/**

View File

@ -161,6 +161,10 @@
SDE sVal;
int iRet;
if(pResult != NULL)
{
pResult[0] = '\0';
}
iRet = LLDnodePtr2First(self->iList);
while(iRet != 0)
{

View File

@ -96,7 +96,7 @@
char *pPtr = NULL;
char *pLogin = NULL;
char *pUser = NULL, *pPasswd = NULL;
char pBuffer[512];
char pBuffer[512], pHost[131];
int iRet;
time_t shit;
@ -178,6 +178,11 @@
}
else
{
NETInfo(self->pCon->pSock,pHost,131);
sprintf(pBuffer,"Accepted connection on socket %d from %s",
self->pCon->pSock->sockid, pHost);
SICSLogWrite(pBuffer,eInternal);
WriteToCommandLog("SYS >", pBuffer);
SendWelcome(self->pCon);
SCSetRights(self->pCon,iRet);
self->iLogin = 1;