- SICS cleanup: removed unused code
This commit is contained in:
962
amor2t.c
962
amor2t.c
@ -1,962 +0,0 @@
|
||||
/*---------------------------------------------------------------------------
|
||||
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
|
||||
|
||||
Introduced DIAFLAG to switch off diaphragm calculation.
|
||||
|
||||
Mark Koennecke, July 2005
|
||||
---------------------------------------------------------------------------*/
|
||||
#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 14
|
||||
|
||||
#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 void clearRunFlags(pAmor2T self)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAXMOT; i++) {
|
||||
self->toStart[i].pMot = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
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;
|
||||
|
||||
clearRunFlags(self);
|
||||
|
||||
/* 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;
|
||||
|
||||
if (ObVal(self->aParameter, DIAFLAG) > .0) {
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
#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;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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;
|
||||
#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;
|
||||
|
||||
clearRunFlags(self);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* calculation for diaphragm 5 */
|
||||
if (ObVal(self->aParameter, DIAFLAG) > .0) {
|
||||
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);
|
||||
}
|
||||
#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 < MAXMOT; i++) {
|
||||
if (self->toStart[i].pMot == NULL) {
|
||||
continue;
|
||||
}
|
||||
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 < MAXMOT; i++) {
|
||||
if (self->toStart[i].pMot == NULL) {
|
||||
continue;
|
||||
}
|
||||
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 < MAXMOT; i++) {
|
||||
if (self->toStart[i].pMot == NULL) {
|
||||
continue;
|
||||
}
|
||||
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 < MAXMOT; i++) {
|
||||
if (self->toStart[i].pMot == NULL) {
|
||||
continue;
|
||||
}
|
||||
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 < MAXMOT; i++) {
|
||||
if (self->toStart[i].pMot == NULL) {
|
||||
continue;
|
||||
}
|
||||
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 < MAXMOT; i++) {
|
||||
if (self->toStart[i].pMot == NULL) {
|
||||
continue;
|
||||
}
|
||||
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));
|
||||
fprintf(fd, "%s diaflag %f \n", name, ObVal(self->aParameter, DIAFLAG));
|
||||
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);
|
||||
sprintf(pBueffel,
|
||||
"%s.diaflag %f \n", name, ObVal(self->aParameter, DIAFLAG));
|
||||
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];
|
||||
const 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, (char *) 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, (char *) 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, (char *) 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, (char *) 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, (char *) 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, (char *) 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, (char *) 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, (char *) 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, (char *) 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, (char *) 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, (char *) 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, (char *) 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);
|
||||
ObParInit(pNew->aParameter, DIAFLAG, "diaflag", 1., 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;
|
||||
}
|
||||
}
|
21
amor2t.h
21
amor2t.h
@ -1,21 +0,0 @@
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
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[]);
|
||||
|
||||
#endif
|
56
amor2t.i
56
amor2t.i
@ -1,56 +0,0 @@
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
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
|
||||
/* flag for diaphragms */
|
||||
#define DIAFLAG 13
|
||||
|
||||
|
||||
typedef struct {
|
||||
pMotor pMot;
|
||||
char pName[80];
|
||||
float fTarget;
|
||||
}MotEntry, *pMotEntry;
|
||||
|
||||
|
||||
|
||||
typedef struct __AMOR2T {
|
||||
pObjectDescriptor pDes;
|
||||
pIDrivable pDriv;
|
||||
pMotor aEngine[MAXMOT];
|
||||
MotEntry toStart[MAXMOT];
|
||||
ObPar *aParameter;
|
||||
}Amor2T;
|
||||
|
||||
|
205
amor2t.tex
205
amor2t.tex
@ -1,205 +0,0 @@
|
||||
\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.
|
||||
\item[run] A flag which determines if this motor is to be run.
|
||||
\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@ 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@@$\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@/* flag for diaphragms */@\\
|
||||
\mbox{}\verb@#define DIAFLAG 13@\\
|
||||
\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}
|
151
amor2t.w
151
amor2t.w
@ -1,151 +0,0 @@
|
||||
\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.
|
||||
\item[run] A flag which determines if this motor is to be run.
|
||||
\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];
|
||||
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[]);
|
||||
@}
|
||||
|
||||
@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
|
||||
/* flag for diaphragms */
|
||||
#define DIAFLAG 13
|
||||
|
||||
@<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
|
||||
@}
|
||||
|
136
amorscan.c
136
amorscan.c
@ -1,136 +0,0 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
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);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
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);
|
||||
AppendScanVar(pVar, fVal);
|
||||
sprintf(pItem, " %-9.9s", pVar->Name);
|
||||
strcat(pHead, pItem);
|
||||
sprintf(pItem, " %-9.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, " %-14ld", 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, " %-14ld", 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, " %-11ld", sCount.Monitors[3]);
|
||||
strcat(pStatus, pItem);
|
||||
strcat(pHead, "Monitor2 ");
|
||||
sprintf(pItem, " %-11ld", sCount.Monitors[4]);
|
||||
strcat(pStatus, pItem);
|
||||
strcat(pHead, "Time ");
|
||||
sprintf(pItem, " %-5.1f", sCount.fTime);
|
||||
strcat(pStatus, pItem);
|
||||
|
||||
/* write progress */
|
||||
strcat(pHead, "\n");
|
||||
strcat(pStatus, "\n");
|
||||
SCWrite(self->pCon, pHead, eLog);
|
||||
SCWrite(self->pCon, pStatus, eLog);
|
||||
|
||||
/* 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;
|
||||
return 1;
|
||||
}
|
14
amorscan.h
14
amorscan.h
@ -1,14 +0,0 @@
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
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
|
57
amorscan.w
57
amorscan.w
@ -1,57 +0,0 @@
|
||||
\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
|
||||
|
||||
@}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
265
dilludriv.c
265
dilludriv.c
@ -1,265 +0,0 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
D I L L U D R I V
|
||||
|
||||
This file contains the implementation of a driver for the Oxford
|
||||
Instruments dillution cryostat using the CC0-510/AVSI temperature
|
||||
controller.
|
||||
|
||||
|
||||
Mark Koennecke, October 1997
|
||||
|
||||
Copyright: see copyright.h
|
||||
----------------------------------------------------------------------------*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <fortify.h>
|
||||
#include <conman.h>
|
||||
#include <servlog.h>
|
||||
#include <fortify.h>
|
||||
|
||||
#include "evdriver.h"
|
||||
#include "hardsup/dillutil.h"
|
||||
#include "hardsup/el734_def.h"
|
||||
#include "hardsup/el734fix.h"
|
||||
#include "dilludriv.h"
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
pDILLU pData;
|
||||
char *pHost;
|
||||
int iPort;
|
||||
int iChannel;
|
||||
int iLastError;
|
||||
char *pTranslationFile;
|
||||
} DILLUDriv, *pDILLUDriv;
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int GetDILLUPos(pEVDriver self, float *fPos)
|
||||
{
|
||||
pDILLUDriv pMe = NULL;
|
||||
int iRet;
|
||||
|
||||
assert(self);
|
||||
pMe = (pDILLUDriv) self->pPrivate;
|
||||
assert(pMe);
|
||||
|
||||
iRet = DILLU_Read(&pMe->pData, fPos);
|
||||
if (iRet != 1) {
|
||||
pMe->iLastError = iRet;
|
||||
return 0;
|
||||
}
|
||||
if ((*fPos < 0) || (*fPos > 1000)) {
|
||||
*fPos = -999.;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int DILLURun(pEVDriver self, float fVal)
|
||||
{
|
||||
pDILLUDriv pMe = NULL;
|
||||
int iRet;
|
||||
|
||||
assert(self);
|
||||
pMe = (pDILLUDriv) self->pPrivate;
|
||||
assert(pMe);
|
||||
|
||||
iRet = DILLU_Set(&pMe->pData, fVal);
|
||||
if (iRet != 1) {
|
||||
pMe->iLastError = iRet;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int DILLUError(pEVDriver self, int *iCode, char *error, int iErrLen)
|
||||
{
|
||||
pDILLUDriv pMe = NULL;
|
||||
|
||||
assert(self);
|
||||
pMe = (pDILLUDriv) self->pPrivate;
|
||||
assert(pMe);
|
||||
|
||||
*iCode = pMe->iLastError;
|
||||
DILLU_Error2Text(&pMe->pData, pMe->iLastError, error, iErrLen);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int DILLUSend(pEVDriver self, char *pCommand, char *pReply,
|
||||
int iLen)
|
||||
{
|
||||
pDILLUDriv pMe = NULL;
|
||||
int iRet;
|
||||
|
||||
assert(self);
|
||||
pMe = (pDILLUDriv) self->pPrivate;
|
||||
assert(pMe);
|
||||
|
||||
iRet = DILLU_Send(&pMe->pData, pCommand, pReply, iLen);
|
||||
if (iRet != 1) {
|
||||
pMe->iLastError = iRet;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int DILLUInit(pEVDriver self)
|
||||
{
|
||||
pDILLUDriv pMe = NULL;
|
||||
int iRet;
|
||||
|
||||
assert(self);
|
||||
pMe = (pDILLUDriv) self->pPrivate;
|
||||
assert(pMe);
|
||||
|
||||
pMe->pData = NULL;
|
||||
iRet = DILLU_Open(&pMe->pData, pMe->pHost, pMe->iPort, pMe->iChannel,
|
||||
0, pMe->pTranslationFile);
|
||||
if (iRet != 1) {
|
||||
pMe->iLastError = iRet;
|
||||
return 0;
|
||||
}
|
||||
DILLU_Config(&pMe->pData, 1000);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int DILLUClose(pEVDriver self)
|
||||
{
|
||||
pDILLUDriv pMe = NULL;
|
||||
int iRet;
|
||||
|
||||
assert(self);
|
||||
pMe = (pDILLUDriv) self->pPrivate;
|
||||
assert(pMe);
|
||||
|
||||
DILLU_Close(&pMe->pData);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int DILLUFix(pEVDriver self, int iError)
|
||||
{
|
||||
pDILLUDriv pMe = NULL;
|
||||
int iRet;
|
||||
|
||||
assert(self);
|
||||
pMe = (pDILLUDriv) 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:
|
||||
DILLUClose(self);
|
||||
iRet = DILLUInit(self);
|
||||
if (iRet) {
|
||||
return DEVREDO;
|
||||
} else {
|
||||
return DEVFAULT;
|
||||
}
|
||||
break;
|
||||
/* handable protocoll errors */
|
||||
case EL734__BAD_TMO:
|
||||
return DEVREDO;
|
||||
break;
|
||||
case DILLU__NODILLFILE:
|
||||
case DILLU__ERRORTABLE:
|
||||
case DILLU__READONLY:
|
||||
case DILLU__OUTOFRANGE:
|
||||
case DILLU__BADMALLOC:
|
||||
case DILLU__FILENOTFOUND:
|
||||
return DEVFAULT;
|
||||
case DILLU__BADREAD:
|
||||
case DILLU__SILLYANSWER:
|
||||
return DEVREDO;
|
||||
default:
|
||||
return DEVFAULT;
|
||||
break;
|
||||
}
|
||||
return DEVFAULT;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int DILLUHalt(pEVDriver * self)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
void KillDILLU(void *pData)
|
||||
{
|
||||
pDILLUDriv pMe = NULL;
|
||||
|
||||
pMe = (pDILLUDriv) pData;
|
||||
assert(pMe);
|
||||
|
||||
if (pMe->pHost) {
|
||||
free(pMe->pHost);
|
||||
}
|
||||
if (pMe->pTranslationFile) {
|
||||
free(pMe->pTranslationFile);
|
||||
}
|
||||
free(pMe);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
pEVDriver CreateDILLUDriv(int argc, char *argv[])
|
||||
{
|
||||
pEVDriver pNew = NULL;
|
||||
pDILLUDriv pSim = NULL;
|
||||
|
||||
/* check for arguments */
|
||||
if (argc < 3) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pNew = CreateEVDriver(argc, argv);
|
||||
pSim = (pDILLUDriv) malloc(sizeof(DILLUDriv));
|
||||
memset(pSim, 0, sizeof(DILLUDriv));
|
||||
if (!pNew || !pSim) {
|
||||
return NULL;
|
||||
}
|
||||
pNew->pPrivate = pSim;
|
||||
pNew->KillPrivate = KillDILLU;
|
||||
|
||||
/* initalise pDILLUDriver */
|
||||
pSim->iLastError = 0;
|
||||
pSim->pHost = strdup(argv[0]);
|
||||
pSim->iPort = atoi(argv[1]);
|
||||
pSim->iChannel = atoi(argv[2]);
|
||||
pSim->pTranslationFile = strdup(argv[3]);
|
||||
|
||||
|
||||
/* initialise function pointers */
|
||||
pNew->SetValue = DILLURun;
|
||||
pNew->GetValue = GetDILLUPos;
|
||||
pNew->Send = DILLUSend;
|
||||
pNew->GetError = DILLUError;
|
||||
pNew->TryFixIt = DILLUFix;
|
||||
pNew->Init = DILLUInit;
|
||||
pNew->Close = DILLUClose;
|
||||
|
||||
return pNew;
|
||||
}
|
15
dilludriv.h
15
dilludriv.h
@ -1,15 +0,0 @@
|
||||
/*------------------------------------------------------------------------
|
||||
D I L L U D R I V
|
||||
|
||||
A SICS driver for thedillution cryostat using the CCO-510/AVSI
|
||||
controller.
|
||||
|
||||
Mark Koennecke, October 1997
|
||||
|
||||
copyright: see copyright.h
|
||||
---------------------------------------------------------------------------*/
|
||||
#ifndef DILLUDRIV
|
||||
#define DILLUDRIV
|
||||
pEVDriver CreateDILLUDriv(int argc, char *argv[]);
|
||||
|
||||
#endif
|
54
dmc.c
54
dmc.c
@ -1,54 +0,0 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
D M C
|
||||
|
||||
this modules purpose is solely to initialise the commands specific to
|
||||
the powder diffractometer DMC.
|
||||
|
||||
Mark Koenencke, March 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 "fortify.h"
|
||||
#include "conman.h"
|
||||
#include "obdes.h"
|
||||
#include "napi.h"
|
||||
#include "nxdata.h"
|
||||
#include "dmc.h"
|
||||
|
||||
int InitDmc(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
AddCommand(pSics, "StoreData", SNStoreDMC, NULL, NULL);
|
||||
return 1;
|
||||
}
|
19
dmc.h
19
dmc.h
@ -1,19 +0,0 @@
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
D M C
|
||||
|
||||
this modules purpose is solely to initialise the commands specific to
|
||||
the powder diffractometer DMC.
|
||||
|
||||
Mark Koenencke, March 1997
|
||||
|
||||
copyright: see implementation file.
|
||||
|
||||
--------------------------------------------------------------------------*/
|
||||
#ifndef SICSDMC
|
||||
#define SICSDMC
|
||||
|
||||
int InitDmc(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
#endif
|
27
dmc.w
27
dmc.w
@ -1,27 +0,0 @@
|
||||
\subsection{DMC module}
|
||||
This module initialises all DMC specific commands. Currently there is only
|
||||
one: StoreData. This does not do much, it is just here as a container for
|
||||
things to come.
|
||||
|
||||
@d Protos @{
|
||||
int InitDmc(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
@}
|
||||
|
||||
@o dmc.h @{
|
||||
/*-------------------------------------------------------------------------
|
||||
D M C
|
||||
|
||||
this modules purpose is solely to initialise the commands specific to
|
||||
the powder diffractometer DMC.
|
||||
|
||||
Mark Koenencke, March 1997
|
||||
|
||||
copyright: see implementation file.
|
||||
|
||||
--------------------------------------------------------------------------*/
|
||||
#ifndef SICSDMC
|
||||
#define SICSDMC
|
||||
@< Protos @>
|
||||
#endif
|
||||
@}
|
20
fowrite.h
20
fowrite.h
@ -1,20 +0,0 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
F O W R I T E
|
||||
|
||||
fowrite is an object for writing FOCUS data files.
|
||||
|
||||
copyright: see copyright.h
|
||||
|
||||
Mark Koennecke, November 1998
|
||||
----------------------------------------------------------------------------*/
|
||||
#ifndef FOWRITE
|
||||
#define FOWRITE
|
||||
|
||||
int FoInstall(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[]);
|
||||
|
||||
|
||||
int FoAction(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[]);
|
||||
|
||||
#endif
|
12
make_gen
12
make_gen
@ -9,18 +9,18 @@
|
||||
.tc.c:
|
||||
tjxp $*.tc $*.c
|
||||
|
||||
OBJ=psi.o buffer.o ruli.o dmc.o nxsans.o nextrics.o sps.o pimotor.o \
|
||||
pipiezo.o sanswave.o faverage.o fowrite.o amor2t.o nxamor.o \
|
||||
OBJ=psi.o buffer.o ruli.o sps.o pimotor.o \
|
||||
pipiezo.o sanswave.o faverage.o \
|
||||
amorstat.o tasinit.o ptasdrive.o tasutil.o tasscan.o swmotor.o \
|
||||
polterwrite.o ecb.o frame.o el734driv.o el734dc.o ecbdriv.o \
|
||||
ecbcounter.o el737driv.o sinqhmdriv.o tdchm.o velodorn.o \
|
||||
velodornier.o docho.o sanscook.o tecsdriv.o itc4driv.o itc4.o\
|
||||
bruker.o ltc11.o A1931.o dilludriv.o eurodriv.o slsmagnet.o \
|
||||
el755driv.o amorscan.o serial.o scontroller.o t_update.o \
|
||||
bruker.o ltc11.o A1931.o eurodriv.o slsmagnet.o \
|
||||
el755driv.o serial.o scontroller.o t_update.o \
|
||||
t_rlp.o t_conv.o el737hpdriv.o dornier2.o el734hp.o \
|
||||
el737hpv2driv.o swmotor2.o tricssupport.o amorcomp.o \
|
||||
$(MZOBJ) amordrive.o amorset.o tcpdornier.o sinqhttp.o\
|
||||
dgrambroadcast.o sinq.o tabledrive.o tcpdocho.o julcho.o \
|
||||
$(MZOBJ) amordrive.o amorset.o sinqhttp.o\
|
||||
dgrambroadcast.o sinq.o tabledrive.o julcho.o \
|
||||
ritastorage.o poldizug.o audinelib.o delcam.o el737hpdrivsps.o \
|
||||
rebin.o sanslirebin.o lmd200.o slsvme.o julprot.o sinqhttpprot.o \
|
||||
pmacprot.o pfeifferprot.o termprot.o phytron.o autowin.o
|
||||
|
@ -7,12 +7,13 @@
|
||||
# Mark Koennecke, December 2009
|
||||
#==========================================================================
|
||||
|
||||
include ../linux_def
|
||||
#include ../linux_def
|
||||
include ../sllinux_def
|
||||
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 $(NI) -I$(TCLINC) -Ihardsup \
|
||||
-I.. -MMD -DCYGNUS -DNONINTF -g $(DFORTIFY) \
|
||||
-I.. -I. -MMD -DCYGNUS -DNONINTF -g $(DFORTIFY) \
|
||||
-Wall -Wno-unused -Wunused-value -Wno-comment -Wno-switch -Werror
|
||||
|
||||
EXTRA=nintf.o
|
||||
|
1369
nextrics.c
1369
nextrics.c
File diff suppressed because it is too large
Load Diff
38
nextrics.h
38
nextrics.h
@ -1,38 +0,0 @@
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
N E X T R I C S
|
||||
|
||||
An object for writing NeXus data files for the four ciclre diffractometer
|
||||
TRICS at PSI. Can be used as basis for writing files for other four
|
||||
circles equiped with a PSD as well.
|
||||
|
||||
copyright: see copyright.h
|
||||
|
||||
Mark Koennecke, April 1998
|
||||
------------------------------------------------------------------------------*/
|
||||
#ifndef NEXTRICS
|
||||
#define NEXTRICS
|
||||
#include <danu.h>
|
||||
|
||||
typedef struct __NexTrics *pNexTrics;
|
||||
|
||||
/*----------------------------- live & death -----------------------------*/
|
||||
pNexTrics CreateNexTrics(pDataNumber pNum, char *pRoot, char *pDict,
|
||||
SicsInterp * pSics);
|
||||
void DeleteNexTrics(void *pData);
|
||||
|
||||
int NexTricsFactory(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
/*----------------------------- interaction ------------------------------*/
|
||||
|
||||
int StartFile(pNexTrics self, SConnection * pCon);
|
||||
|
||||
int ReopenFile(pNexTrics self, char *filename);
|
||||
|
||||
int DumpFrame(pNexTrics self, SConnection * pCon);
|
||||
|
||||
int NexTricsAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
|
||||
#endif
|
775
nxamor.c
775
nxamor.c
@ -1,775 +0,0 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
N X A M O R
|
||||
|
||||
Routines for writing NeXus files for the reflectometer AMOR at PSI.
|
||||
|
||||
copyright: see copyright.h
|
||||
|
||||
|
||||
Mark Koennecke, September 1999
|
||||
Updated, Mark Koennecke, August 2001
|
||||
Updated to store TOF-monitor, Mark Koennecke, September 2002
|
||||
--------------------------------------------------------------------------*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "fortify.h"
|
||||
#include "sics.h"
|
||||
#include "nxdict.h"
|
||||
#include "nxutil.h"
|
||||
#include "scan.h"
|
||||
#include "scan.i"
|
||||
#include "HistMem.h"
|
||||
#include "counter.h"
|
||||
#include "nxamor.h"
|
||||
#include "obpar.h"
|
||||
#include "motor.h"
|
||||
#include "status.h"
|
||||
|
||||
#define MAXMOT 13 /* must be same as in amor2t.c */
|
||||
#include "amor2t.i"
|
||||
#include "amor2t.h"
|
||||
|
||||
/* some defines for some names */
|
||||
static char AMORDICT[1024] = "/home/amor/amor_sics/amor.dic";
|
||||
#define INSTNAME "AMOR at SINQ, PSI"
|
||||
#define SOURCENAME "Spallation source SINQ"
|
||||
#define SOURCETYPE "Continous flux spallation source"
|
||||
#define CHOPPERNAME "Dornier Chopper System"
|
||||
|
||||
/*
|
||||
The rough size of each detector chunk to write in TOF mode
|
||||
(currently 16MB)
|
||||
#define TOFBLOCK 8192000
|
||||
#define TOFBLOCK 16384000
|
||||
*/
|
||||
#define TOFBLOCK 65536000
|
||||
|
||||
/*
|
||||
a pointer to amor2t which we need for a couple of parameters
|
||||
*/
|
||||
pAmor2T pAmor = NULL;
|
||||
|
||||
/*
|
||||
if to save psd data in TOF mode or not. This is in order to save time
|
||||
when measureing TOF with a single detector only.
|
||||
*/
|
||||
|
||||
static int psdSave = 1;
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
static void WriteDiaphragm(NXhandle hfil, NXdict hdict, int i,
|
||||
SConnection * pCon)
|
||||
{
|
||||
char pThing[30];
|
||||
|
||||
|
||||
sprintf(pThing, "d%1.1dt", i);
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, pThing, pThing);
|
||||
sprintf(pThing, "d%1.1db", i);
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, pThing, pThing);
|
||||
sprintf(pThing, "d%1.1dl", i);
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, pThing, pThing);
|
||||
sprintf(pThing, "d%1.1dr", i);
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, pThing, pThing);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
int WriteAmorHeader(char *file, SConnection * pCon)
|
||||
{
|
||||
NXhandle hfil;
|
||||
NXdict hdict;
|
||||
int iRet;
|
||||
char pBueffel[512], pThing[80];
|
||||
CounterMode eMode;
|
||||
CommandList *pCom = NULL;
|
||||
float fVal;
|
||||
|
||||
/* open files */
|
||||
NXsetcache(TOFBLOCK);
|
||||
iRet = NXopen(file, NXACC_CREATE5, &hfil);
|
||||
if (iRet != NX_OK) {
|
||||
snprintf(pBueffel, 511, "ERROR: cannot open file %s for writing",
|
||||
file);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
iRet = NXDinitfromfile(AMORDICT, &hdict);
|
||||
if (iRet != NX_OK) {
|
||||
snprintf(pBueffel, 511, "ERROR: cannot open dictionary file %s",
|
||||
AMORDICT);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
snprintf(pBueffel, 511, "Writing to: %s", file);
|
||||
SCWrite(pCon, pBueffel, eWarning);
|
||||
|
||||
/* put some global information */
|
||||
SNXSPutGlobals(hfil, file, "AMOR", pCon);
|
||||
SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "etitle", "title");
|
||||
SNXFormatTime(pBueffel, 512);
|
||||
NXDputalias(hfil, hdict, "estart", pBueffel);
|
||||
|
||||
/* instrument vGroup */
|
||||
NXDputalias(hfil, hdict, "iname", INSTNAME);
|
||||
|
||||
/* source */
|
||||
NXDputalias(hfil, hdict, "sname", SOURCENAME);
|
||||
NXDputalias(hfil, hdict, "stype", SOURCETYPE);
|
||||
|
||||
/* chopper */
|
||||
NXDputalias(hfil, hdict, "cname", CHOPPERNAME);
|
||||
SNXSPutDrivable(pServ->pSics, pCon, hfil, hdict, "chopperspeed", "crot");
|
||||
SNXSPutDrivable(pServ->pSics, pCon, hfil, hdict, "chopper1phase",
|
||||
"cphase1");
|
||||
SNXSPutDrivable(pServ->pSics, pCon, hfil, hdict, "chopper2phase",
|
||||
"cphase2");
|
||||
|
||||
SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "crot",
|
||||
"chopperrotation");
|
||||
|
||||
/* frame overlap mirror */
|
||||
SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "fomname", "fomname");
|
||||
SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "fodist", "fomdist");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "fomh", "ftz");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "fomom", "fom");
|
||||
|
||||
/* first Diaphragm */
|
||||
WriteDiaphragm(hfil, hdict, 1, pCon);
|
||||
sprintf(pThing, "d%1.1ddist", 1);
|
||||
SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, pThing, pThing);
|
||||
|
||||
/* polarizing, monochromating mirror */
|
||||
SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "polname", "polname");
|
||||
SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "poldist", "poldist");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "polz", "moz");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "polom", "mom");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "poly", "mty");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "polzom", "mtz");
|
||||
|
||||
/* second Diaphragm */
|
||||
WriteDiaphragm(hfil, hdict, 2, pCon);
|
||||
sprintf(pThing, "d%1.1ddist", 2);
|
||||
SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, pThing, pThing);
|
||||
|
||||
/* third Diaphragm */
|
||||
WriteDiaphragm(hfil, hdict, 3, pCon);
|
||||
sprintf(pThing, "d%1.1ddist", 3);
|
||||
SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, pThing, pThing);
|
||||
|
||||
/* sample table */
|
||||
SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "saname", "sample");
|
||||
SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "stdist", "sampledist");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "somheight", "stz");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "schi", "sch");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "somega", "som");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "stheight", "soz");
|
||||
fVal = ObVal(pAmor->aParameter, PARDH);
|
||||
NXDputalias(hfil, hdict, "baseheight", &fVal);
|
||||
|
||||
|
||||
/* fourth Diaphragm */
|
||||
WriteDiaphragm(hfil, hdict, 4, pCon);
|
||||
fVal = ObVal(pAmor->aParameter, PARDD4);
|
||||
NXDputalias(hfil, hdict, "d4dist", &fVal);
|
||||
fVal = ObVal(pAmor->aParameter, PARD4H);
|
||||
NXDputalias(hfil, hdict, "d4base", &fVal);
|
||||
|
||||
/* analyzer */
|
||||
SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "anname", "ananame");
|
||||
SNXSPutVariable(pServ->pSics, pCon, hfil, hdict, "andist", "anadist");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "anoz", "atz");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "anom", "aom");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "antz", "aoz");
|
||||
fVal = ObVal(pAmor->aParameter, PARADIS);
|
||||
NXDputalias(hfil, hdict, "adis", &fVal);
|
||||
fVal = ObVal(pAmor->aParameter, PARANA);
|
||||
NXDputalias(hfil, hdict, "abase", &fVal);
|
||||
|
||||
|
||||
/* fifth Diaphragm!!!!!!!!! */
|
||||
WriteDiaphragm(hfil, hdict, 5, pCon);
|
||||
fVal = ObVal(pAmor->aParameter, PARDD5);
|
||||
NXDputalias(hfil, hdict, "d5dist", &fVal);
|
||||
fVal = ObVal(pAmor->aParameter, PARD5H);
|
||||
NXDputalias(hfil, hdict, "d5base", &fVal);
|
||||
|
||||
/* counting data */
|
||||
pCom = FindCommand(pServ->pSics, "counter");
|
||||
if (pCom) {
|
||||
if (pCom->pData) {
|
||||
eMode = GetCounterMode((pCounter) pCom->pData);
|
||||
if (eMode == eTimer) {
|
||||
strcpy(pBueffel, "timer");
|
||||
} else {
|
||||
strcpy(pBueffel, "monitor");
|
||||
}
|
||||
NXDputalias(hfil, hdict, "cnmode", pBueffel);
|
||||
fVal = GetCounterPreset((pCounter) pCom->pData);
|
||||
NXDputalias(hfil, hdict, "cnpreset", &fVal);
|
||||
}
|
||||
} else {
|
||||
SCWrite(pCon, "WARNING: failed to find counter!", eWarning);
|
||||
}
|
||||
NXclose(&hfil);
|
||||
NXDclose(hdict, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
int WriteAmorScan(char *file, SConnection * pCon, pScanData pScan)
|
||||
{
|
||||
NXhandle hfil;
|
||||
NXdict hdict;
|
||||
int iRet, i;
|
||||
char pBueffel[512], pDefinition[1024];
|
||||
CommandList *pCom = NULL;
|
||||
float fVal;
|
||||
float *fAxis = NULL;
|
||||
long *lData = NULL;
|
||||
int *iData = NULL;
|
||||
|
||||
/* open files */
|
||||
iRet = NXopen(file, NXACC_RDWR, &hfil);
|
||||
if (iRet != NX_OK) {
|
||||
sprintf(pBueffel, "ERROR: cannot open file %s for writing", file);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
iRet = NXDinitfromfile(AMORDICT, &hdict);
|
||||
if (iRet != NX_OK) {
|
||||
sprintf(pBueffel, "ERROR: cannot open dictionary file %s", AMORDICT);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* allocate memory for writing scan data */
|
||||
fAxis = (float *) malloc(pScan->iNP * sizeof(float));
|
||||
lData = (long *) malloc(pScan->iNP * sizeof(long));
|
||||
iData = (int *) malloc(pScan->iNP * sizeof(int));
|
||||
if ((!fAxis) || (!lData) || (!iData)) {
|
||||
SCWrite(pCon, "ERROR: out of memory in WriteAmorScan", eError);
|
||||
return 0;
|
||||
}
|
||||
memset(fAxis, 0, pScan->iNP * sizeof(float));
|
||||
memset(lData, 0, pScan->iNP * sizeof(long));
|
||||
memset(iData, 0, pScan->iNP * sizeof(int));
|
||||
|
||||
/* write scan variables */
|
||||
for (i = 0; i < pScan->iScanVar; i++) {
|
||||
/* build definition string */
|
||||
NXDget(hdict, "scanroot", pBueffel, 512);
|
||||
strcpy(pDefinition, pBueffel);
|
||||
strcat(pDefinition, " ");
|
||||
GetScanVarName(pScan, i, pBueffel, 512);
|
||||
strcat(pDefinition, pBueffel);
|
||||
sprintf(pBueffel, " -rank 1 -dim {%d} ", pScan->iNP);
|
||||
strcat(pDefinition, pBueffel);
|
||||
if (i == 0) {
|
||||
strcat(pDefinition, " -attr {axis,1}");
|
||||
}
|
||||
/* get data and write */
|
||||
GetScanVar(pScan, i, fAxis, pScan->iNP);
|
||||
NXDputdef(hfil, hdict, pDefinition, fAxis);
|
||||
if (i == 0) {
|
||||
NXDget(hdict, "sdana", pBueffel, 512);
|
||||
NXDdeflink(hfil, hdict, pBueffel, pDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Write counted data: Here there is a convention which has to be
|
||||
valid in amorscan as well: GetCounts gets the main detector.
|
||||
GetMonitor 0 the second detector, GetMonitor 1 the first detector
|
||||
other spin, GetMonitor 2, the second detector the other spin,
|
||||
getMonitor 3, the first monitor, getMonitor 4 the second monitor
|
||||
*/
|
||||
sprintf(pBueffel, "%d", pScan->iNP);
|
||||
NXDupdate(hdict, "scanlength", pBueffel);
|
||||
GetScanCounts(pScan, lData, pScan->iNP);
|
||||
for (i = 0; i < pScan->iNP; i++) {
|
||||
iData[i] = (int) lData[i];
|
||||
}
|
||||
NXDputalias(hfil, hdict, "spinupup", iData);
|
||||
NXDaliaslink(hfil, hdict, "sdana", "spinupup");
|
||||
GetScanMonitor(pScan, 0, lData, pScan->iNP);
|
||||
for (i = 0; i < pScan->iNP; i++) {
|
||||
iData[i] = (int) lData[i];
|
||||
}
|
||||
NXDputalias(hfil, hdict, "spinuplo", iData);
|
||||
NXDaliaslink(hfil, hdict, "sdana", "spinuplo");
|
||||
|
||||
/* monitors */
|
||||
GetScanMonitor(pScan, 3, lData, pScan->iNP);
|
||||
for (i = 0; i < pScan->iNP; i++) {
|
||||
iData[i] = (int) lData[i];
|
||||
}
|
||||
NXDputalias(hfil, hdict, "smonitor1", iData);
|
||||
GetScanMonitor(pScan, 4, lData, pScan->iNP);
|
||||
for (i = 0; i < pScan->iNP; i++) {
|
||||
iData[i] = (int) lData[i];
|
||||
}
|
||||
NXDputalias(hfil, hdict, "smonitor2", iData);
|
||||
|
||||
/* to be added: polarizing mode, possibly coz, cox, com etc. */
|
||||
|
||||
/* a few motors which may or may not be useful */
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "sdetx", "cox");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "sdetom", "com");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "sdetheight", "coz");
|
||||
|
||||
/* close and go */
|
||||
NXclose(&hfil);
|
||||
NXDclose(hdict, NULL);
|
||||
free(fAxis);
|
||||
free(lData);
|
||||
free(iData);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
WriteTOFDetector writes the histogram memory data in TOF mode. As
|
||||
the histogram memory can become quite large at AMOR, the data is
|
||||
read and stored in chunks if it is to big. All this is handled
|
||||
in this routine.
|
||||
-------------------------------------------------------------------------*/
|
||||
static int WriteTOFDetector(char *name, pHistMem pHM, int *iDim,
|
||||
NXhandle hfil, NXdict hdict,
|
||||
SConnection * pCon)
|
||||
{
|
||||
int nChunk, chunkSize, iChunk[3], i, iStart[3], nTime, iRet;
|
||||
long iLength;
|
||||
HistInt *lData = NULL;
|
||||
char pBueffel[132];
|
||||
const float *fTime;
|
||||
int start;
|
||||
|
||||
fTime = GetHistTimeBin(pHM, &nTime);
|
||||
iDim[2] = nTime;
|
||||
iLength = iDim[0] * iDim[1] * iDim[2];
|
||||
if ((iLength * 4) < TOFBLOCK) {
|
||||
sprintf(pBueffel, " -chunk {%d,%d,%d} ", iDim[0], iDim[1], iDim[2]);
|
||||
NXDupdate(hdict, "chunk", pBueffel);
|
||||
lData = (HistInt *) malloc(iLength * sizeof(HistInt));
|
||||
if (!lData) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: out of memory, failed to write histogram", eError);
|
||||
SCSetInterrupt(pCon, eAbortBatch);
|
||||
return 0;
|
||||
}
|
||||
memset(lData, 0, iLength * sizeof(HistInt));
|
||||
iRet = GetHistogramDirect(pHM, pCon,
|
||||
0, 0, iLength, lData,
|
||||
iLength * sizeof(HistInt));
|
||||
if (!iRet) {
|
||||
SCWrite(pCon, "ERROR: failed to read Hm data", eError);
|
||||
SCSetInterrupt(pCon, eAbortBatch);
|
||||
free(lData);
|
||||
return 0;
|
||||
}
|
||||
SicsWait(2);
|
||||
NXDputalias(hfil, hdict, name, lData);
|
||||
NXDputalias(hfil, hdict, "detchunk", iDim);
|
||||
NXDaliaslink(hfil, hdict, "dana", name);
|
||||
} else {
|
||||
/*
|
||||
implement chunked writing. We strive to write layers in Y. The
|
||||
number of chunks needs to fulfill three conditions then:
|
||||
- multiple of xSize* timeBin;
|
||||
- close to TOFBLOCK in size
|
||||
- divide Y without remainder.
|
||||
*/
|
||||
iChunk[0] = iDim[0];
|
||||
iChunk[2] = iDim[2];
|
||||
iChunk[1] = 1;
|
||||
chunkSize = iDim[0] * iDim[2];
|
||||
for (i = 1; i < 64; i++) {
|
||||
if ((iDim[1] % i) == 0) {
|
||||
if (i * chunkSize * sizeof(HistInt) < TOFBLOCK) {
|
||||
iChunk[1] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
sprintf(pBueffel, "Segmented TOF data in %d chunks",
|
||||
iDim[1] / iChunk[1]);
|
||||
SCWrite(pCon, pBueffel, eWarning);
|
||||
/*
|
||||
now we have a chunkSize, lets go and write!
|
||||
*/
|
||||
NXDputalias(hfil, hdict, "detchunk", iChunk);
|
||||
chunkSize = iChunk[1] * iChunk[0] * iChunk[2];
|
||||
sprintf(pBueffel, " -chunk {%d,%d,%d} ", iChunk[0], iChunk[1],
|
||||
iChunk[2]);
|
||||
NXDupdate(hdict, "chunk", pBueffel);
|
||||
lData = (HistInt *) malloc(chunkSize * sizeof(HistInt));
|
||||
if (!lData) {
|
||||
SCWrite(pCon, "ERROR: out of memory while writing TOF data", eError);
|
||||
SCSetInterrupt(pCon, eAbortBatch);
|
||||
return 0;
|
||||
}
|
||||
NXDopenalias(hfil, hdict, name);
|
||||
for (i = 0; i < iDim[1] / iChunk[1]; i++) {
|
||||
memset(lData, 0, chunkSize * sizeof(HistInt));
|
||||
iRet = GetHistogramDirect(pHM, pCon,
|
||||
0, i * chunkSize, (i + 1) * chunkSize,
|
||||
lData, chunkSize * sizeof(HistInt));
|
||||
if (!iRet) {
|
||||
SCWrite(pCon, "ERROR: failed to read HM data", eError);
|
||||
SCSetInterrupt(pCon, eAbortBatch);
|
||||
free(lData);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
yield a little in order to allow other clients to receive a
|
||||
response. Also allow for interrupting.
|
||||
*/
|
||||
SicsWait(2);
|
||||
|
||||
iStart[0] = 0;
|
||||
iStart[1] = i * iChunk[1];
|
||||
iStart[2] = 0;
|
||||
NXputslab(hfil, lData, iStart, iChunk);
|
||||
sprintf(pBueffel, "Wrote chunk %d", i);
|
||||
SCWrite(pCon, pBueffel, eWarning);
|
||||
/*
|
||||
yield a little in order to allow other clients to receive a
|
||||
response. Also allow for interrupting.
|
||||
*/
|
||||
SicsWait(2);
|
||||
}
|
||||
/*
|
||||
close groups till root
|
||||
*/
|
||||
NXclosedata(hfil);
|
||||
NXclosegroup(hfil);
|
||||
NXclosegroup(hfil);
|
||||
NXclosegroup(hfil);
|
||||
|
||||
/*
|
||||
make link
|
||||
*/
|
||||
NXDaliaslink(hfil, hdict, "dana", name);
|
||||
NXDaliaslink(hfil, hdict, "dana", "detchunk");
|
||||
|
||||
}
|
||||
if (lData)
|
||||
free(lData);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
int WriteAmorTOF(char *file, SConnection * pCon, pHistMem pHM)
|
||||
{
|
||||
NXhandle hfil;
|
||||
NXdict hdict;
|
||||
int iRet, i, iLength;
|
||||
char pBueffel[512];
|
||||
float fVal, *fAxis = NULL, *fTime2 = NULL;
|
||||
CommandList *pCom = NULL;
|
||||
const float *fTime;
|
||||
HistInt *lData = NULL, lVal;
|
||||
int detxsize, detysize, iDim[MAXDIM];
|
||||
|
||||
|
||||
/* open files */
|
||||
iRet = NXopen(file, NXACC_RDWR, &hfil);
|
||||
if (iRet != NX_OK) {
|
||||
sprintf(pBueffel, "ERROR: cannot open file %s for writing", file);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
iRet = NXDinitfromfile(AMORDICT, &hdict);
|
||||
if (iRet != NX_OK) {
|
||||
sprintf(pBueffel, "ERROR: cannot open dictionary file %s", AMORDICT);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* a few motors which may or may not be useful */
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "detx", "cox");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "detom", "com");
|
||||
SNXSPutMotor(pServ->pSics, pCon, hfil, hdict, "detheight", "coz");
|
||||
|
||||
/* write counter related stuff */
|
||||
pCom = FindCommand(pServ->pSics, "counter");
|
||||
if (pCom) {
|
||||
if (pCom->pData) {
|
||||
fVal = GetCountTime((pCounter) pCom->pData, pCon);
|
||||
NXDputalias(hfil, hdict, "cntime", &fVal);
|
||||
|
||||
/* the assignment of monitors has to be checked once
|
||||
the Schlumpf is done
|
||||
*/
|
||||
lVal = GetMonitor((pCounter) pCom->pData, 1, pCon);
|
||||
NXDputalias(hfil, hdict, "cnmon1", &lVal);
|
||||
lVal = GetMonitor((pCounter) pCom->pData, 4, pCon);
|
||||
NXDputalias(hfil, hdict, "cnmon2", &lVal);
|
||||
}
|
||||
} else {
|
||||
SCWrite(pCon, "WARNING: failed to find counter!", eWarning);
|
||||
}
|
||||
|
||||
/*
|
||||
find dimensions of detector
|
||||
*/
|
||||
GetHistDim(pHM, iDim, &iLength);
|
||||
detxsize = iDim[0];
|
||||
detysize = iDim[1];
|
||||
/* update detector size */
|
||||
sprintf(pBueffel, "%d", detxsize);
|
||||
NXDupdate(hdict, "detxsize", pBueffel);
|
||||
sprintf(pBueffel, "%d", detysize);
|
||||
NXDupdate(hdict, "detysize", pBueffel);
|
||||
|
||||
|
||||
/* write two axis */
|
||||
if (detxsize > detysize)
|
||||
iLength = detxsize;
|
||||
else
|
||||
iLength = detysize;
|
||||
|
||||
fAxis = (float *) malloc(iLength * sizeof(float));
|
||||
if (!fAxis) {
|
||||
SCWrite(pCon, "ERROR: out of memory in WriteAmorTOF", eError);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < detxsize; i++) {
|
||||
fAxis[i] = (float) i;
|
||||
}
|
||||
NXDputalias(hfil, hdict, "detxx", fAxis);
|
||||
for (i = 0; i < detysize; i++) {
|
||||
fAxis[i] = (float) i;
|
||||
}
|
||||
NXDputalias(hfil, hdict, "dety", fAxis);
|
||||
NXDaliaslink(hfil, hdict, "dana", "detxx");
|
||||
NXDaliaslink(hfil, hdict, "dana", "dety");
|
||||
free(fAxis);
|
||||
|
||||
|
||||
/* add height and distances */
|
||||
fVal = ObVal(pAmor->aParameter, PARDS);
|
||||
NXDputalias(hfil, hdict, "detdist", &fVal);
|
||||
fVal = ObVal(pAmor->aParameter, PARDDH);
|
||||
NXDputalias(hfil, hdict, "detbase", &fVal);
|
||||
|
||||
|
||||
/* deal with time binning */
|
||||
fTime = GetHistTimeBin(pHM, &iLength);
|
||||
iDim[2] = iLength;
|
||||
fTime2 = (float *) malloc(iLength * sizeof(float));
|
||||
if (fTime2) {
|
||||
for (i = 0; i < iLength; i++) {
|
||||
fTime2[i] = fTime[i] / 10.;
|
||||
}
|
||||
sprintf(pBueffel, "%d", iLength);
|
||||
NXDupdate(hdict, "timebin", pBueffel);
|
||||
NXDputalias(hfil, hdict, "dettime", fTime2);
|
||||
NXDputalias(hfil, hdict, "singletime", fTime2);
|
||||
NXDaliaslink(hfil, hdict, "dana", "dettime");
|
||||
free(fTime2);
|
||||
fTime2 = NULL;
|
||||
} else {
|
||||
SCWrite(pCon, "ERROR: out of memory while writing time binning",
|
||||
eError);
|
||||
SCSetInterrupt(pCon, eAbortBatch);
|
||||
NXclose(&hfil);
|
||||
NXDclose(hdict, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* finally get histogram */
|
||||
if (iDim[2] == 2) { /* 2D data, no time binning on this detector */
|
||||
iLength = detxsize * detysize;
|
||||
lData = (HistInt *) malloc(iLength * sizeof(HistInt));
|
||||
if (!lData) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: out of memory, failed to write histogram", eError);
|
||||
NXclose(&hfil);
|
||||
NXDclose(hdict, NULL);
|
||||
SCSetInterrupt(pCon, eAbortBatch);
|
||||
return 0;
|
||||
}
|
||||
memset(lData, 0, iLength * sizeof(HistInt));
|
||||
iRet = GetHistogram(pHM, pCon, 0, 0, iLength,
|
||||
lData, iLength * sizeof(HistInt));
|
||||
if (!iRet) {
|
||||
SCWrite(pCon, "ERROR: failed to read HM", eError);
|
||||
SCSetInterrupt(pCon, eAbortBatch);
|
||||
NXclose(&hfil);
|
||||
NXDclose(hdict, NULL);
|
||||
return 0;
|
||||
}
|
||||
NXDputalias(hfil, hdict, "spinup2d", lData);
|
||||
NXDaliaslink(hfil, hdict, "dana", "spinup2d");
|
||||
} else {
|
||||
if (psdSave) {
|
||||
iRet = WriteTOFDetector("spinup", pHM, iDim, hfil, hdict, pCon);
|
||||
if (!iRet) {
|
||||
NXclose(&hfil);
|
||||
NXDclose(hdict, NULL);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
SCWrite(pCon, "PSD writing supressed!", eWarning);
|
||||
}
|
||||
#define MAXSINGLE 3
|
||||
/*
|
||||
now get and write single detectors
|
||||
*/
|
||||
iLength = iDim[0] * iDim[1] * iDim[2];
|
||||
lData = (HistInt *) malloc(MAXSINGLE * iDim[2] * sizeof(HistInt));
|
||||
if (!lData) {
|
||||
SCWrite(pCon, "ERROR: out of memory while writing single detectors",
|
||||
eError);
|
||||
SCSetInterrupt(pCon, eAbortBatch);
|
||||
NXclose(&hfil);
|
||||
NXDclose(hdict, NULL);
|
||||
return 0;
|
||||
} else {
|
||||
memset(lData, 0, MAXSINGLE * iDim[2] * sizeof(HistInt));
|
||||
iRet = GetHistogramDirect(pHM, pCon, 0, iLength,
|
||||
iLength + MAXSINGLE * iDim[2],
|
||||
lData,
|
||||
MAXSINGLE * iDim[2] * sizeof(HistInt));
|
||||
if (!iRet) {
|
||||
SCWrite(pCon, "ERROR: failed to read single detector HM data",
|
||||
eError);
|
||||
SCSetInterrupt(pCon, eAbortBatch);
|
||||
free(lData);
|
||||
NXclose(&hfil);
|
||||
NXDclose(hdict, NULL);
|
||||
return 0;
|
||||
}
|
||||
NXDputalias(hfil, hdict, "singleup", lData);
|
||||
NXDaliaslink(hfil, hdict, "singledana", "singleup");
|
||||
NXDaliaslink(hfil, hdict, "singledana", "singletime");
|
||||
/*
|
||||
the TOF monitor
|
||||
*/
|
||||
NXDputalias(hfil, hdict, "singletofmon", lData + 2 * iDim[2]);
|
||||
NXDaliaslink(hfil, hdict, "dana", "singletofmon");
|
||||
NXDaliaslink(hfil, hdict, "singledana", "singletofmon");
|
||||
}
|
||||
}
|
||||
|
||||
/* to do: add polarizing code */
|
||||
|
||||
if (lData)
|
||||
free(lData);
|
||||
|
||||
NXclose(&hfil);
|
||||
NXDclose(hdict, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static pHistMem pMeme = NULL;
|
||||
|
||||
int AmorStore(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
char pBueffel[512], *pFile = NULL;
|
||||
int iRet, iFlag;
|
||||
Status oldStatus;
|
||||
|
||||
/*
|
||||
if arguments, check for psdsave
|
||||
*/
|
||||
if (argc > 1) {
|
||||
strtolower(argv[1]);
|
||||
if (strcmp(argv[1], "psdsave") == 0) {
|
||||
if (argc > 2) {
|
||||
psdSave = atof(argv[2]);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else {
|
||||
sprintf(pBueffel, "storeamor.psdSave = %d", psdSave);
|
||||
SCWrite(pCon, pBueffel, eValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pFile = SNXMakeFileName(pSics, pCon);
|
||||
sprintf(pBueffel, "Writing file %s .....", pFile);
|
||||
SCWrite(pCon, pBueffel, eWarning);
|
||||
|
||||
oldStatus = GetStatus();
|
||||
SetStatus(eWriting);
|
||||
LockDeviceExecutor(pServ->pExecutor);
|
||||
iRet = WriteAmorHeader(pFile, pCon);
|
||||
if (iRet) {
|
||||
iRet = WriteAmorTOF(pFile, pCon, pMeme);
|
||||
}
|
||||
SetStatus(oldStatus);
|
||||
UnlockDeviceExecutor(pServ->pExecutor);
|
||||
free(pFile);
|
||||
SCSendOK(pCon);
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
int AmorStoreMake(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
CommandList *pCom = NULL;
|
||||
char pBueffel[512];
|
||||
int iRet;
|
||||
|
||||
if (argc < 3) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: insufficient number of arguments to AmorStoreMake",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we need a parameter which is the name of the histogram memory */
|
||||
pCom = FindCommand(pServ->pSics, argv[1]);
|
||||
if (!pCom) {
|
||||
sprintf(pBueffel, "ERROR: Histogram memory %s NOT found", argv[1]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
if (!pCom->pData) {
|
||||
sprintf(pBueffel, "ERROR: Histogram memory %s NOT found", argv[1]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
pMeme = (pHistMem) pCom->pData;
|
||||
|
||||
/* we need another parameter which is the name of the
|
||||
2theta calculation module
|
||||
*/
|
||||
pCom = FindCommand(pServ->pSics, argv[2]);
|
||||
if (!pCom) {
|
||||
sprintf(pBueffel, "ERROR: amor2T module %s NOT found", argv[2]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
if (!pCom->pData) {
|
||||
sprintf(pBueffel, "ERROR: amor2t module %s NOT found", argv[2]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
pAmor = (pAmor2T) pCom->pData;
|
||||
if (argc > 3) {
|
||||
strncpy(AMORDICT, argv[3], 1023);
|
||||
}
|
||||
|
||||
|
||||
/* install command */
|
||||
iRet = AddCommand(pSics, "storeamor", AmorStore, NULL, NULL);
|
||||
if (!iRet) {
|
||||
sprintf(pBueffel, "ERROR: duplicate command amorstore NOT created");
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
29
nxamor.h
29
nxamor.h
@ -1,29 +0,0 @@
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
N X A M O R
|
||||
|
||||
Some routines for writing NeXus files for the reflectometer AMOR at
|
||||
SINQ.
|
||||
|
||||
copyright: see copyright.h
|
||||
|
||||
Mark Koennecke, September 1999
|
||||
----------------------------------------------------------------------*/
|
||||
#ifndef NXAMOR
|
||||
#define NXAMOR
|
||||
#include <scan.h>
|
||||
#include <HistMem.h>
|
||||
|
||||
int WriteAmorHeader(char *file, SConnection * pCon);
|
||||
|
||||
int WriteAmorScan(char *file, SConnection * pCon, pScanData pScan);
|
||||
|
||||
int WriteAmorTOF(char *file, SConnection * pCon, pHistMem pHM);
|
||||
|
||||
int AmorStore(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
int AmorStoreMake(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
|
||||
#endif
|
71
nxamor.tex
71
nxamor.tex
@ -1,71 +0,0 @@
|
||||
\subsection{AMOR NeXus Routines}
|
||||
This module implements a few functions for writing NeXus data files
|
||||
for the reflectoemter AMOR at SINQ, PSI. Nothing very exciting here:
|
||||
this is mostly boring repetetive code. Three functions are defined:
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap1}
|
||||
$\langle$namor {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ int WriteAmorHeader(char *file, SConnection *pCon);@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ int WriteAmorScan(char *file, SConnection *pCon, pScanData pScan);@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ int WriteAmorTOF(char *file, SConnection *pCon, pHistMem pHM);@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ int AmorStore(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
|
||||
\mbox{}\verb@ int argc, char *argv[]);@\\
|
||||
\mbox{}\verb@ int AmorStoreMake(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[WriteAmorHeader] writes all the AMOR header information and the
|
||||
zillions of motors.
|
||||
\item[WriteAmorScan] writes data when AMOR was operated in scanning
|
||||
mode.
|
||||
\item[WriteAmorTOF] writes AMOR data when used with the PSD in
|
||||
time-of-flight mode.
|
||||
\item[AmorStore] the command function implementing the storeamor
|
||||
command.
|
||||
\item[AmorStoreMake] the initialization function which creates the
|
||||
storeamor command.
|
||||
\end{description}
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap2}
|
||||
\verb@"nxamor.h"@ {\footnotesize ? }$\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@/*------------------------------------------------------------------------@\\
|
||||
\mbox{}\verb@ N X A M O R@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ Some routines for writing NeXus files for the reflectometer AMOR at@\\
|
||||
\mbox{}\verb@ SINQ.@\\
|
||||
\mbox{}\verb@ @\\
|
||||
\mbox{}\verb@ copyright: see copyright.h@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ Mark Koennecke, September 1999@\\
|
||||
\mbox{}\verb@----------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@#ifndef NXAMOR@\\
|
||||
\mbox{}\verb@#define NXAMOR@\\
|
||||
\mbox{}\verb@#include <scan.h>@\\
|
||||
\mbox{}\verb@#include <HistMem.h>@\\
|
||||
\mbox{}\verb@@$\langle$namor {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@#endif@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-2ex}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
50
nxamor.w
50
nxamor.w
@ -1,50 +0,0 @@
|
||||
\subsection{AMOR NeXus Routines}
|
||||
This module implements a few functions for writing NeXus data files
|
||||
for the reflectoemter AMOR at SINQ, PSI. Nothing very exciting here:
|
||||
this is mostly boring repetetive code. Three functions are defined:
|
||||
|
||||
@d namor @{
|
||||
int WriteAmorHeader(char *file, SConnection *pCon);
|
||||
|
||||
int WriteAmorScan(char *file, SConnection *pCon, pScanData pScan);
|
||||
|
||||
int WriteAmorTOF(char *file, SConnection *pCon, pHistMem pHM);
|
||||
|
||||
int AmorStore(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
int AmorStoreMake(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
@}
|
||||
|
||||
\begin{description}
|
||||
\item[WriteAmorHeader] writes all the AMOR header information and the
|
||||
zillions of motors.
|
||||
\item[WriteAmorScan] writes data when AMOR was operated in scanning
|
||||
mode.
|
||||
\item[WriteAmorTOF] writes AMOR data when used with the PSD in
|
||||
time-of-flight mode.
|
||||
\item[AmorStore] the command function implementing the storeamor
|
||||
command.
|
||||
\item[AmorStoreMake] the initialization function which creates the
|
||||
storeamor command.
|
||||
\end{description}
|
||||
|
||||
@o nxamor.h @{
|
||||
/*------------------------------------------------------------------------
|
||||
N X A M O R
|
||||
|
||||
Some routines for writing NeXus files for the reflectometer AMOR at
|
||||
SINQ.
|
||||
|
||||
copyright: see copyright.h
|
||||
|
||||
Mark Koennecke, September 1999
|
||||
----------------------------------------------------------------------*/
|
||||
#ifndef NXAMOR
|
||||
#define NXAMOR
|
||||
#include <scan.h>
|
||||
#include <HistMem.h>
|
||||
@<namor@>
|
||||
#endif
|
||||
@}
|
705
nxsans.c
705
nxsans.c
@ -1,705 +0,0 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
N X S A N S
|
||||
|
||||
a module of utility functions which serve to write Nexus
|
||||
data files for SANS.
|
||||
|
||||
Mark Koennecke, August 1997 - November 1998
|
||||
|
||||
Updated to support the larger detector resolution and possible
|
||||
TOF and stroboscopic modes, Mark Koennecke, February 2001
|
||||
|
||||
Added additional monitors for stroboscopic gummi mode,
|
||||
Mark Koennecke, September 2002
|
||||
|
||||
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 <time.h>
|
||||
#include "fortify.h"
|
||||
#include "sics.h"
|
||||
#include "sicsvar.h"
|
||||
#include "napi.h"
|
||||
#include "nxdict.h"
|
||||
#include "modriv.h"
|
||||
#include "motor.h"
|
||||
#include "nxutil.h"
|
||||
#include "nxdata.h"
|
||||
#include "countdriv.h"
|
||||
#include "counter.h"
|
||||
#include "danu.h"
|
||||
#include "HistMem.h"
|
||||
#include "velo.h"
|
||||
#include "sps.h"
|
||||
#include "udpquieck.h"
|
||||
#include "mumo.h"
|
||||
#include "sanswave.h"
|
||||
|
||||
|
||||
#define HISTNAME "banana"
|
||||
#define SAMPLETABLE "sampletable"
|
||||
|
||||
static int gummiFlag = 0; /* a flag indicating stroboscopic, or gummi mode */
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static void SNError(void *pData, char *text)
|
||||
{
|
||||
SConnection *pCon;
|
||||
|
||||
assert(pData);
|
||||
pCon = (SConnection *) pData;
|
||||
SCWrite(pCon, text, eError);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
NXhandle SNXStartSANS(SConnection * pCon, SicsInterp * pSics)
|
||||
{
|
||||
NXhandle pFile = NULL;
|
||||
char *filename = NULL;
|
||||
pSicsVariable pVar = NULL;
|
||||
int iStat;
|
||||
char pBueffel[512];
|
||||
|
||||
/* get a filename */
|
||||
filename = SNXMakeFileName(pSics, pCon);
|
||||
if (!filename) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create a Nexus file */
|
||||
NXopen(filename, NXACC_CREATE, &pFile);
|
||||
if (!pFile) {
|
||||
SCWrite(pCon, "ERROR: cannot create data file ", eError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* tell Uwe User what we are doing */
|
||||
sprintf(pBueffel, "Writing %s ......", filename);
|
||||
SCWrite(pCon, pBueffel, eWarning);
|
||||
|
||||
/* store global attributes */
|
||||
iStat = NXputattr(pFile, "file_name", filename,
|
||||
strlen(filename) + 1, NX_CHAR);
|
||||
if (iStat == NX_ERROR) {
|
||||
SCWrite(pCon, "ERROR: writing file_name attribute to Nexus file",
|
||||
eError);
|
||||
}
|
||||
|
||||
/* throw away filename, no longer needed */
|
||||
free(filename);
|
||||
|
||||
/* write creation time */
|
||||
SNXFormatTime(pBueffel, 512);
|
||||
iStat = NXputattr(pFile, "file_time", pBueffel,
|
||||
strlen(pBueffel) + 1, NX_CHAR);
|
||||
if (iStat == NX_ERROR) {
|
||||
SCWrite(pCon, "ERROR: writing date attribute to Nexus file", eError);
|
||||
}
|
||||
pVar = FindVariable(pSics, "instrument");
|
||||
if (pVar) {
|
||||
iStat = NXputattr(pFile, "instrument", pVar->text,
|
||||
strlen(pVar->text) + 1, NX_CHAR);
|
||||
if (iStat == NX_ERROR) {
|
||||
SCWrite(pCon, "ERROR: writing instrument attribute to Nexus file",
|
||||
eError);
|
||||
}
|
||||
}
|
||||
pVar = NULL;
|
||||
pVar = FindVariable(pSics, "user");
|
||||
if (pVar) {
|
||||
iStat = NXputattr(pFile, "owner", pVar->text,
|
||||
strlen(pVar->text) + 1, NX_CHAR);
|
||||
if (iStat == NX_ERROR) {
|
||||
SCWrite(pCon, "ERROR: writing owner attribute to Nexus file",
|
||||
eError);
|
||||
}
|
||||
}
|
||||
|
||||
pVar = NULL;
|
||||
pVar = FindVariable(pSics, "adress");
|
||||
if (pVar) {
|
||||
iStat = NXputattr(pFile, "owner_adress", pVar->text,
|
||||
strlen(pVar->text) + 1, NX_CHAR);
|
||||
if (iStat == NX_ERROR) {
|
||||
SCWrite(pCon, "ERROR: writing owner_adress attribute to Nexus file",
|
||||
eError);
|
||||
}
|
||||
}
|
||||
pVar = NULL;
|
||||
pVar = FindVariable(pSics, "phone");
|
||||
if (pVar) {
|
||||
iStat = NXputattr(pFile, "owner_telephone_number", pVar->text,
|
||||
strlen(pVar->text) + 1, NX_CHAR);
|
||||
if (iStat == NX_ERROR) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: writing owner_telephone_number attribute to Nexus file",
|
||||
eError);
|
||||
}
|
||||
}
|
||||
pVar = NULL;
|
||||
pVar = FindVariable(pSics, "fax");
|
||||
if (pVar) {
|
||||
iStat = NXputattr(pFile, "owner_fax_number", pVar->text,
|
||||
strlen(pVar->text) + 1, NX_CHAR);
|
||||
if (iStat == NX_ERROR) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: writing owner_fax_number attribute to Nexus file",
|
||||
eError);
|
||||
}
|
||||
}
|
||||
pVar = NULL;
|
||||
pVar = FindVariable(pSics, "email");
|
||||
if (pVar) {
|
||||
iStat = NXputattr(pFile, "owner_email", pVar->text,
|
||||
strlen(pVar->text) + 1, NX_CHAR);
|
||||
if (iStat == NX_ERROR) {
|
||||
SCWrite(pCon, "ERROR: writing owner_email attribute to Nexus file",
|
||||
eError);
|
||||
}
|
||||
}
|
||||
pVar = NULL;
|
||||
return pFile;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int SNMakeSANS(SConnection * pCon, SicsInterp * pSics, NXdict pDict)
|
||||
{
|
||||
NXhandle Nfil = NULL;
|
||||
char pBueffel[512];
|
||||
float fVal;
|
||||
int iVal, iSet;
|
||||
int iAxis[256];
|
||||
int i, iRet;
|
||||
long lVal;
|
||||
HistInt *lData = NULL;
|
||||
const float *fTime = NULL;
|
||||
CommandList *pCom = NULL;
|
||||
pHistMem self = NULL;
|
||||
CounterMode eMode;
|
||||
pVelSel pVelo = NULL;
|
||||
pSPS pSiem = NULL;
|
||||
const char *pNamPos = NULL;
|
||||
float fRot, fTilt, fLambda;
|
||||
pDummy pDum;
|
||||
pIDrivable pDrive;
|
||||
int iDim[MAXDIM], nDim, histSize, iStart;
|
||||
|
||||
/* start file */
|
||||
Nfil = SNXStartSANS(pCon, pSics);
|
||||
if (!Nfil) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
during all this, no extensive error checking will be done,
|
||||
just write the error and continue, save at all cost
|
||||
*/
|
||||
|
||||
/* put all this global information */
|
||||
SNXSPutVariable(pSics, pCon, Nfil, pDict, "etitle", "title");
|
||||
SNXSPutVariable(pSics, pCon, Nfil, pDict, "etime", "starttime");
|
||||
SNXFormatTime(pBueffel, 511);
|
||||
NXDputalias(Nfil, pDict, "endtime", pBueffel);
|
||||
strcpy(pBueffel, "SANS at SINQ,PSI");
|
||||
NXDputalias(Nfil, pDict, "iname", pBueffel);
|
||||
strcpy(pBueffel, "SINQ at PSI,Villigen, Switzerland");
|
||||
NXDputalias(Nfil, pDict, "sname", pBueffel);
|
||||
strcpy(pBueffel, "Spallation");
|
||||
NXDputalias(Nfil, pDict, "stype", pBueffel);
|
||||
|
||||
/* put the velocity selector data */
|
||||
NXDputalias(Nfil, pDict, "vname", "Dornier Velocity Selector");
|
||||
|
||||
fRot = 0.;
|
||||
fTilt = 0.;
|
||||
pCom = FindCommand(pSics, "nvs");
|
||||
if (pCom) {
|
||||
pVelo = (pVelSel) pCom->pData;
|
||||
if (!pVelo) {
|
||||
SCWrite(pCon, "WARNING: Velocity Selctor not found", eWarning);
|
||||
}
|
||||
iRet = VSGetRotation(pVelo, &fVal);
|
||||
if (!iRet) {
|
||||
SCWrite(pCon, "WARNING: failed to read velocity selector speed",
|
||||
eWarning);
|
||||
} else {
|
||||
fRot = fVal;
|
||||
NXDputalias(Nfil, pDict, "vrot", &fVal);
|
||||
}
|
||||
iRet = VSGetTilt(pVelo, &fTilt);
|
||||
if (!iRet) {
|
||||
SCWrite(pCon, "WARNING: failed to read velocity selector tilt angle",
|
||||
eWarning);
|
||||
}
|
||||
}
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "vtilt", "tilt");
|
||||
CalculateLambda(fRot, fTilt, &fLambda);
|
||||
NXDputalias(Nfil, pDict, "vlambda", &fLambda);
|
||||
|
||||
|
||||
/* monitor 1 */
|
||||
pCom = FindCommand(pSics, HISTNAME);
|
||||
if (!pCom) {
|
||||
sprintf(pBueffel, "ERROR: histogram memory %s not found", HISTNAME);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
self = (pHistMem) pCom->pData;
|
||||
assert(self);
|
||||
lVal = GetHistMonitor(self, 0, pCon);
|
||||
iVal = (int) lVal;
|
||||
NXDputalias(Nfil, pDict, "m1counts", &iVal);
|
||||
lVal = GetHistMonitor(self, 4, pCon);
|
||||
iVal = (int) lVal;
|
||||
NXDputalias(Nfil, pDict, "pbcounts", &iVal);
|
||||
|
||||
/* the collimator */
|
||||
pCom = FindCommand(pSics, "sps2");
|
||||
if (!pCom) {
|
||||
SCWrite(pCon, "WARNING: sps-unit for reading collimator NOT found",
|
||||
eWarning);
|
||||
} else {
|
||||
pSiem = (pSPS) pCom->pData;
|
||||
if (!pSiem) {
|
||||
SCWrite(pCon, "WARNING: sps-unit for reading collimator NOT found",
|
||||
eWarning);
|
||||
} else {
|
||||
iRet = SPSGetSANS(pSiem, &fVal);
|
||||
if (iRet <= 0) {
|
||||
SCWrite(pCon, "WARNING: Failed to read SPS", eWarning);
|
||||
} else {
|
||||
NXDputalias(Nfil, pDict, "colli", &fVal);
|
||||
}
|
||||
/* as we got the sps, get the attenuator as well */
|
||||
iRet = SPSGetStatus(pSiem, 38, &iSet);
|
||||
if (iRet < 0) {
|
||||
SCWrite(pCon, "WARNING: Failed to read SPS", eWarning);
|
||||
} else {
|
||||
if (iSet) {
|
||||
iVal = 0;
|
||||
}
|
||||
}
|
||||
iRet = SPSGetStatus(pSiem, 39, &iSet);
|
||||
if (iRet < 0) {
|
||||
SCWrite(pCon, "WARNING: Failed to read SPS", eWarning);
|
||||
} else {
|
||||
if (iSet) {
|
||||
iVal = 1;
|
||||
}
|
||||
}
|
||||
iRet = SPSGetStatus(pSiem, 40, &iSet);
|
||||
if (iRet < 0) {
|
||||
SCWrite(pCon, "WARNING: Failed to read SPS", eWarning);
|
||||
} else {
|
||||
if (iSet) {
|
||||
iVal = 2;
|
||||
}
|
||||
}
|
||||
iRet = SPSGetStatus(pSiem, 41, &iSet);
|
||||
if (iRet < 0) {
|
||||
SCWrite(pCon, "WARNING: Failed to read SPS", eWarning);
|
||||
} else {
|
||||
if (iSet) {
|
||||
iVal = 3;
|
||||
}
|
||||
}
|
||||
iRet = SPSGetStatus(pSiem, 42, &iSet);
|
||||
if (iRet < 0) {
|
||||
SCWrite(pCon, "WARNING: Failed to read SPS", eWarning);
|
||||
} else {
|
||||
if (iSet) {
|
||||
iVal = 4;
|
||||
}
|
||||
}
|
||||
iRet = SPSGetStatus(pSiem, 43, &iSet);
|
||||
if (iRet < 0) {
|
||||
SCWrite(pCon, "WARNING: Failed to read SPS", eWarning);
|
||||
} else {
|
||||
if (iSet) {
|
||||
iVal = 5;
|
||||
}
|
||||
}
|
||||
NXDputalias(Nfil, pDict, "atti", &iVal);
|
||||
}
|
||||
}
|
||||
|
||||
/* the sample */
|
||||
SNXSPutVariable(pSics, pCon, Nfil, pDict, "san", "sample");
|
||||
SNXSPutVariable(pSics, pCon, Nfil, pDict, "saenv", "environment");
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "sax", "sax");
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "say", "say");
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "saz", "saz");
|
||||
SNXSPutMotorNull(pSics, pCon, Nfil, pDict, "saxn", "sax");
|
||||
SNXSPutMotorNull(pSics, pCon, Nfil, pDict, "sayn", "say");
|
||||
SNXSPutMotorNull(pSics, pCon, Nfil, pDict, "sazn", "saz");
|
||||
|
||||
|
||||
/* goniometer */
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "gphi", "gphi");
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "gtheta", "gtheta");
|
||||
SNXSPutMotorNull(pSics, pCon, Nfil, pDict, "gphin", "gphi");
|
||||
SNXSPutMotorNull(pSics, pCon, Nfil, pDict, "gthetan", "gtheta");
|
||||
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "saom", "som");
|
||||
SNXSPutMotorNull(pSics, pCon, Nfil, pDict, "saomn", "som");
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "sapos", "spos");
|
||||
SNXSPutMotorNull(pSics, pCon, Nfil, pDict, "saposn", "spos");
|
||||
pCom = FindCommand(pSics, SAMPLETABLE);
|
||||
if (pCom) {
|
||||
if (pCom->pData) {
|
||||
pNamPos = FindNamPos((pMulMot) pCom->pData, pCon);
|
||||
if (pNamPos) {
|
||||
NXDputalias(Nfil, pDict, "sanampos", (char *) pNamPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* write sample environment here */
|
||||
pCom = FindCommand(pSics, "temperature");
|
||||
if (pCom) {
|
||||
pDum = (pDummy) pCom->pData;
|
||||
pDrive = pDum->pDescriptor->GetInterface(pDum, DRIVEID);
|
||||
if (pDrive) { /* a proper environment device */
|
||||
fVal = pDrive->GetValue(pDum, pCon);
|
||||
NXDputalias(Nfil, pDict, "satemp", &fVal);
|
||||
}
|
||||
}
|
||||
pCom = FindCommand(pSics, "magnet");
|
||||
if (pCom) {
|
||||
pDum = (pDummy) pCom->pData;
|
||||
pDrive = pDum->pDescriptor->GetInterface(pDum, DRIVEID);
|
||||
if (pDrive) { /* a proper environment device */
|
||||
fVal = pDrive->GetValue(pDum, pCon);
|
||||
NXDputalias(Nfil, pDict, "samag", &fVal);
|
||||
}
|
||||
}
|
||||
|
||||
/* magnet motors. This instrument has motorized magnets crawling
|
||||
through the hall */
|
||||
pCom = FindCommand(pSics, "mom");
|
||||
if (pCom) {
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "mom", "mom");
|
||||
}
|
||||
pCom = FindCommand(pSics, "mz");
|
||||
if (pCom) {
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "mz", "mz");
|
||||
}
|
||||
|
||||
|
||||
/* put Beam Stop */
|
||||
/* read beamstop number */
|
||||
iVal = 1;
|
||||
pCom = FindCommand(pSics, "sps1");
|
||||
if (!pCom) {
|
||||
SCWrite(pCon, "WARNING: sps-unit for reading beamstop NOT found",
|
||||
eWarning);
|
||||
} else {
|
||||
pSiem = (pSPS) pCom->pData;
|
||||
if (!pSiem) {
|
||||
SCWrite(pCon, "WARNING: sps-unit for reading beamstop NOT found",
|
||||
eWarning);
|
||||
} else {
|
||||
iRet = SPSGetStatus(pSiem, 8, &iSet);
|
||||
if (iRet < 0) {
|
||||
SCWrite(pCon, "WARNING: Failed to read SPS", eWarning);
|
||||
} else {
|
||||
if (iSet) {
|
||||
iVal = 2;
|
||||
}
|
||||
}
|
||||
iRet = SPSGetStatus(pSiem, 9, &iSet);
|
||||
if (iRet < 0) {
|
||||
SCWrite(pCon, "WARNING: Failed to read SPS", eWarning);
|
||||
} else {
|
||||
if (iSet) {
|
||||
iVal = 3;
|
||||
}
|
||||
}
|
||||
iRet = SPSGetStatus(pSiem, 10, &iSet);
|
||||
if (iRet < 0) {
|
||||
SCWrite(pCon, "WARNING: Failed to read SPS", eWarning);
|
||||
} else {
|
||||
if (iSet) {
|
||||
iVal = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NXDputalias(Nfil, pDict, "bst", &iVal);
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "vsx", "BeamStopX");
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "vsy", "BeamStopY");
|
||||
SNXSPutMotorNull(pSics, pCon, Nfil, pDict, "vsxnull", "BeamStopX");
|
||||
SNXSPutMotorNull(pSics, pCon, Nfil, pDict, "vsynull", "BeamStopY");
|
||||
|
||||
/* what this is all about: the detector */
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "ddx", "DetectorX");
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "ddy", "DetectorY");
|
||||
SNXSPutMotorNull(pSics, pCon, Nfil, pDict, "ddxn", "DetectorX");
|
||||
SNXSPutMotorNull(pSics, pCon, Nfil, pDict, "ddyn", "DetectorY");
|
||||
SNXSPutMotor(pSics, pCon, Nfil, pDict, "ddchi", "DetectorRotation");
|
||||
pCom = FindCommand(pSics, HISTNAME);
|
||||
if (!pCom) {
|
||||
sprintf(pBueffel, "ERROR: histogram memory %s not found", HISTNAME);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
self = (pHistMem) pCom->pData;
|
||||
assert(self);
|
||||
eMode = GetHistCountMode(self);
|
||||
if (eMode == eTimer) {
|
||||
strcpy(pBueffel, "Timer");
|
||||
} else {
|
||||
strcpy(pBueffel, "Monitor");
|
||||
}
|
||||
NXDputalias(Nfil, pDict, "ddm", pBueffel);
|
||||
fVal = GetHistPreset(self);
|
||||
NXDputalias(Nfil, pDict, "ddp", &fVal);
|
||||
lVal = GetHistMonitor(self, 1, pCon);
|
||||
iVal = (int) lVal;
|
||||
NXDputalias(Nfil, pDict, "ddmo", &iVal);
|
||||
fVal = GetHistCountTime(self, pCon);
|
||||
NXDputalias(Nfil, pDict, "ddtime", &fVal);
|
||||
|
||||
/*
|
||||
Deal with actual histogram. Due to stroboscopic modes and the
|
||||
new detector electronics we need to find out about the size
|
||||
ourselves now. And possibly write time binning information.
|
||||
*/
|
||||
GetHistDim(self, iDim, &nDim);
|
||||
/*
|
||||
handle time binning
|
||||
*/
|
||||
fTime = GetHistTimeBin(self, &iVal);
|
||||
if (iVal > 2) {
|
||||
NXDputalias(Nfil, pDict, "ddtb", (void *) fTime);
|
||||
nDim = 3;
|
||||
iDim[2] = iVal;
|
||||
}
|
||||
|
||||
histSize = 1;
|
||||
for (i = 0; i < nDim; i++) {
|
||||
histSize *= iDim[i];
|
||||
}
|
||||
lData = (HistInt *) malloc(histSize * sizeof(HistInt));
|
||||
if (!lData) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: out of memory, FAILED to store data, file corrupt",
|
||||
eError);
|
||||
NXclose(&Nfil);
|
||||
return 0;
|
||||
}
|
||||
GetHistogram(self, pCon, 0, 0, histSize, lData,
|
||||
histSize * sizeof(HistInt));
|
||||
sprintf(pBueffel, " %d ", iDim[0]);
|
||||
NXDupdate(pDict, "dim1", pBueffel);
|
||||
sprintf(pBueffel, " %d ", iDim[1]);
|
||||
NXDupdate(pDict, "dim2", pBueffel);
|
||||
if (nDim == 2) {
|
||||
sprintf(pBueffel, " -rank 2 -dim {%d,%d} ", iDim[0], iDim[1]);
|
||||
NXDupdate(pDict, "countdim", pBueffel);
|
||||
} else if (nDim == 3) {
|
||||
sprintf(pBueffel, " -rank 3 -dim {%d,%d,%d} ", iDim[0], iDim[1],
|
||||
iDim[2]);
|
||||
NXDupdate(pDict, "countdim", pBueffel);
|
||||
sprintf(pBueffel, " %d ", iDim[2]);
|
||||
NXDupdate(pDict, "timedim", pBueffel);
|
||||
}
|
||||
NXDputalias(Nfil, pDict, "ddcounts", lData);
|
||||
free(lData);
|
||||
|
||||
/* write x and y axis */
|
||||
for (i = 0; i < iDim[0]; i++) {
|
||||
iAxis[i] = i;
|
||||
}
|
||||
NXDputalias(Nfil, pDict, "ddcx", iAxis);
|
||||
for (i = 0; i < iDim[1]; i++) {
|
||||
iAxis[i] = i;
|
||||
}
|
||||
NXDputalias(Nfil, pDict, "ddcy", iAxis);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
write gummi monitors when apropriate
|
||||
*/
|
||||
if (nDim == 3 && gummiFlag != 0) {
|
||||
histSize = 3 * iDim[2];
|
||||
lData = (HistInt *) malloc(histSize * sizeof(HistInt));
|
||||
if (lData == NULL) {
|
||||
SCWrite(pCon, "WARNING: failed to allocate memory for monitors",
|
||||
eWarning);
|
||||
} else {
|
||||
memset(lData, 0, histSize * sizeof(HistInt));
|
||||
iStart = iDim[0] * iDim[1] * iDim[2];
|
||||
GetHistogramDirect(self, pCon, 0, iStart, iStart + histSize,
|
||||
lData, histSize * sizeof(HistInt));
|
||||
NXDputalias(Nfil, pDict, "gummimon1", lData);
|
||||
NXDputalias(Nfil, pDict, "gummimon2", lData + iDim[2]);
|
||||
NXDputalias(Nfil, pDict, "gummimon3", lData + 2 * iDim[2]);
|
||||
free(lData);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
write detector temperature. It is a hot one............
|
||||
*/
|
||||
if (pSiem) {
|
||||
iRet = SPSGetADC(pSiem, 1, &iVal);
|
||||
if (iRet) {
|
||||
fVal = iVal / 269.9;
|
||||
NXDputalias(Nfil, pDict, "ddtemp", &fVal);
|
||||
}
|
||||
}
|
||||
|
||||
/* do the linking in th data vgroup */
|
||||
NXDaliaslink(Nfil, pDict, "dan", "ddcounts");
|
||||
NXDaliaslink(Nfil, pDict, "dan", "ddcx");
|
||||
NXDaliaslink(Nfil, pDict, "dan", "ddcy");
|
||||
NXDaliaslink(Nfil, pDict, "dan", "ddmo");
|
||||
NXDaliaslink(Nfil, pDict, "dan", "vlambda");
|
||||
if (nDim == 3) {
|
||||
NXDaliaslink(Nfil, pDict, "dan", "ddtb");
|
||||
}
|
||||
|
||||
/* send quieck message for automatic copying */
|
||||
i = 131;
|
||||
iVal = NX_CHAR;
|
||||
NXgetattr(Nfil, "file_name", pBueffel, &i, &iVal);
|
||||
SendQuieck(QUIECK, pBueffel);
|
||||
/* close this and go ............. */
|
||||
NXclose(&Nfil);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*------------------- The Mechanics for setting Up ------------------------*/
|
||||
typedef struct {
|
||||
pObjectDescriptor pDes;
|
||||
NXdict pDict;
|
||||
} DictStruct, *pDictStruct;
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static pDictStruct MakeDictStruct(char *pFile)
|
||||
{
|
||||
pDictStruct pNew = NULL;
|
||||
int iRet;
|
||||
|
||||
pNew = (pDictStruct) malloc(sizeof(DictStruct));
|
||||
if (!pNew) {
|
||||
return NULL;
|
||||
}
|
||||
memset(pNew, 0, sizeof(DictStruct));
|
||||
pNew->pDes = CreateDescriptor("StoreData");
|
||||
if (!pNew->pDes) {
|
||||
free(pNew);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iRet = NXDinitfromfile(pFile, &(pNew->pDict));
|
||||
if (iRet != NX_OK) {
|
||||
DeleteDescriptor(pNew->pDes);
|
||||
free(pNew);
|
||||
return NULL;
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static void KillDictStruct(void *pData)
|
||||
{
|
||||
pDictStruct self = NULL;
|
||||
|
||||
self = (pDictStruct) pData;
|
||||
assert(self);
|
||||
|
||||
if (self->pDes) {
|
||||
DeleteDescriptor(self->pDes);
|
||||
}
|
||||
if (self->pDict) {
|
||||
NXDclose(self->pDict, NULL);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int SNStoreSANS(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
char pBueffel[80];
|
||||
pDictStruct self = NULL;
|
||||
self = (pDictStruct) pData;
|
||||
|
||||
assert(self);
|
||||
assert(pCon);
|
||||
assert(pSics);
|
||||
|
||||
if (argc > 1) {
|
||||
strtolower(argv[1]);
|
||||
if (strcmp(argv[1], "gummi") == 0) {
|
||||
if (argc > 2) {
|
||||
if (!SCMatchRights(pCon, usMugger)) {
|
||||
return 0;
|
||||
}
|
||||
gummiFlag = atoi(argv[2]);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else {
|
||||
sprintf(pBueffel, "%s.gummi = %d", argv[0], gummiFlag);
|
||||
SCWrite(pCon, pBueffel, eValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SNMakeSANS(pCon, pSics, self->pDict);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int InitSANS(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
pDictStruct pNew = NULL;
|
||||
char pBueffel[512];
|
||||
|
||||
if (argc < 2) {
|
||||
SCWrite(pCon, "ERROR: not enough arguments for IniSANS", eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pNew = MakeDictStruct(argv[1]);
|
||||
if (!pNew) {
|
||||
sprintf(pBueffel, "ERROR: failed to initialise NXDDL from file %s",
|
||||
argv[1]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
AddCommand(pSics, "StoreData", SNStoreSANS, KillDictStruct, pNew);
|
||||
return 1;
|
||||
}
|
17
nxsans.h
17
nxsans.h
@ -1,17 +0,0 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
N X S A N S
|
||||
|
||||
Prototypes for some more useful functions from the SANS data writing
|
||||
module which may ne used in other parts of SICS.
|
||||
|
||||
Mark Koennecke, December 1997
|
||||
---------------------------------------------------------------------------*/
|
||||
#ifndef NXSANS
|
||||
#define NXSANS
|
||||
int InitSANS(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
int SNStoreSANS(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
|
||||
#endif
|
@ -23,6 +23,7 @@
|
||||
#include "sicsvar.h"
|
||||
#include "polterwrite.h"
|
||||
#include "sicsvar.h"
|
||||
#include "nxscript.h"
|
||||
|
||||
/*
|
||||
diaphragm1 - chopper
|
||||
@ -233,7 +234,7 @@ static void PoldiStart(pPolterdi self, SConnection * pCon)
|
||||
pCounter pCount;
|
||||
|
||||
/* create filename */
|
||||
self->pFile = SNXMakeFileName(pServ->pSics, pCon);
|
||||
self->pFile = makeFilename(pServ->pSics, pCon);
|
||||
if (!self->pFile) {
|
||||
SCWrite(pCon, "ERROR: Extra severe: failed to create data file name",
|
||||
eError);
|
||||
|
44
psi.c
44
psi.c
@ -16,16 +16,10 @@
|
||||
#include <tcl.h>
|
||||
#include <site.h>
|
||||
#include "buffer.h"
|
||||
#include "dmc.h"
|
||||
#include "nxsans.h"
|
||||
#include "nextrics.h"
|
||||
#include "sps.h"
|
||||
#include "pimotor.h"
|
||||
#include "sanswave.h"
|
||||
#include "faverage.h"
|
||||
#include "fowrite.h"
|
||||
#include "amor2t.h"
|
||||
#include "nxamor.h"
|
||||
#include "amorstat.h"
|
||||
#include "tas.h"
|
||||
#include "swmotor.h"
|
||||
@ -42,11 +36,9 @@
|
||||
#include "bruker.h"
|
||||
#include "ltc11.h"
|
||||
#include "A1931.h"
|
||||
#include "dilludriv.h"
|
||||
#include "eurodriv.h"
|
||||
#include "el755driv.h"
|
||||
#include <evdriver.i>
|
||||
#include "amorscan.h"
|
||||
#include "serial.h"
|
||||
#include "fomerge.h"
|
||||
#include "remob.h"
|
||||
@ -57,11 +49,6 @@
|
||||
#include "sinqhttp.h"
|
||||
#include "poldizug.h"
|
||||
#include "autowin.h"
|
||||
/*
|
||||
from tcpdornier.c
|
||||
*/
|
||||
extern int VelSelTcpFactory(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[]);
|
||||
/*
|
||||
* from julcho.c
|
||||
*/
|
||||
@ -128,17 +115,11 @@ static pSite sitePSI = NULL;
|
||||
static void AddPsiCommands(SicsInterp * pInter)
|
||||
{
|
||||
AddCommand(pInter, "MakeRuenBuffer", InitBufferSys, NULL, NULL);
|
||||
AddCommand(pInter, "InitDMC", InitDmc, NULL, NULL);
|
||||
AddCommand(pInter, "InitSANS", InitSANS, NULL, NULL);
|
||||
AddCommand(pInter, "MakeTRICSNEXUS", NexTricsFactory, NULL, NULL);
|
||||
AddCommand(pInter, "MakeTRICSSupport", MakeTricsSupport, NULL, NULL);
|
||||
AddCommand(pInter, "MakeSPS", SPSFactory, NULL, NULL);
|
||||
AddCommand(pInter, "MakePIMotor", PIMotorFactory, NULL, NULL);
|
||||
AddCommand(pInter, "MakeSANSWave", MakeSANSWave, NULL, NULL);
|
||||
AddCommand(pInter, "MakeFocusAverager", MakeFA, NULL, NULL);
|
||||
AddCommand(pInter, "FocusInstall", FoInstall, NULL, NULL);
|
||||
AddCommand(pInter, "MakeAmor2T", Amor2TFactory, NULL, NULL);
|
||||
AddCommand(pInter, "MakeStoreAmor", AmorStoreMake, NULL, NULL);
|
||||
AddCommand(pInter, "MakeAmorStatus", AmorStatusFactory, NULL, NULL);
|
||||
AddCommand(pInter, "MakeTAS", TASFactory, NULL, NULL);
|
||||
AddCommand(pInter, "MakeSWMotor", MakeSWMotor, NULL, NULL);
|
||||
@ -152,7 +133,6 @@ static void AddPsiCommands(SicsInterp * pInter)
|
||||
AddCommand(pInter, "MakeSinq", SinqFactory, NULL, NULL);
|
||||
AddCommand(pInter, "MakeTableDrive", TableDriveFactory, NULL, NULL);
|
||||
AddCommand(pInter, "MakeAmorSet", AmorSetFactory, NULL, NULL);
|
||||
AddCommand(pInter, "MakeTCPSelector", VelSelTcpFactory, NULL, NULL);
|
||||
AddCommand(pInter, "MakeJulCho", JulChoFactory, NULL, NULL);
|
||||
AddCommand(pInter, "MakeRitaFix", MakeRitaFix, NULL, NULL);
|
||||
AddCommand(pInter, "MakePoldiReiss", MakePoldiReiss, NULL, NULL);
|
||||
@ -167,9 +147,6 @@ static void AddPsiCommands(SicsInterp * pInter)
|
||||
/*---------------------------------------------------------------------*/
|
||||
static void RemovePsiCommands(SicsInterp * pSics)
|
||||
{
|
||||
RemoveCommand(pSics, "InitDMC");
|
||||
RemoveCommand(pSics, "InitSANS");
|
||||
RemoveCommand(pSics, "MakeTRICSNEXUS");
|
||||
RemoveCommand(pSics, "MakeTRICSSupport");
|
||||
RemoveCommand(pSics, "MakeSPS");
|
||||
RemoveCommand(pSics, "MakePIMotor");
|
||||
@ -177,10 +154,8 @@ static void RemovePsiCommands(SicsInterp * pSics)
|
||||
RemoveCommand(pSics, "MakeFocusAverager");
|
||||
RemoveCommand(pSics, "FocusInstall");
|
||||
RemoveCommand(pSics, "InstallFocusMerge");
|
||||
RemoveCommand(pSics, "MakeAmor2T");
|
||||
RemoveCommand(pSics, "MakeStoreAmor");
|
||||
RemoveCommand(pSics, "MakeAmorStatus");
|
||||
RemoveCommand(pSics, "MakeTCPSelector");
|
||||
RemoveCommand(pSics, "MakeJulCho");
|
||||
RemoveCommand(pSics, "MakeRitaFix");
|
||||
RemoveCommand(pSics, "MakePoldiReiss");
|
||||
@ -370,7 +345,6 @@ static pVelSelDriv CreatePsiVelSelDriv(char *name, char *array,
|
||||
extern pCodri MakeDoChoDriver(char *pHost, int iPort, int iChannel,
|
||||
int iSingle);
|
||||
extern pCodri MakeCookerDriver(char *pHost, int iPort, int iChannel);
|
||||
extern pCodri MakeTcpDoChoDriver(char *tclArray, SConnection * pCon);
|
||||
/*-------------------------------------------------------------------*/
|
||||
static pCodri CreatePsiController(SConnection * pCon, int argc,
|
||||
char *argv[])
|
||||
@ -412,14 +386,6 @@ static pCodri CreatePsiController(SConnection * pCon, int argc,
|
||||
}
|
||||
}
|
||||
pNew = MakeDoChoDriver(argv[1], iPort, iChannel, iSingle);
|
||||
} else if (strcmp(argv[0], "tcpdocho") == 0) {
|
||||
if (argc < 2) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: insufficient number of argumets for creating TcpDoCho",
|
||||
eError);
|
||||
return NULL;
|
||||
}
|
||||
return MakeTcpDoChoDriver(argv[1], pCon);
|
||||
} else if (strcmp(argv[0], "sanscook") == 0) {
|
||||
if (argc < 4) {
|
||||
SCWrite(pCon,
|
||||
@ -545,12 +511,6 @@ static pEVControl InstallPsiEnvironmentController(SicsInterp * pSics,
|
||||
commandInstalled = 1;
|
||||
}
|
||||
}
|
||||
} else if (strcmp(argv[3], "dillu") == 0) {
|
||||
checkError = 1;
|
||||
pDriv = CreateDILLUDriv(argc - 4, &argv[4]);
|
||||
if (pDriv != NULL) {
|
||||
pNew = CreateEVController(pDriv, argv[2], &status);
|
||||
}
|
||||
} else if (strcmp(argv[3], "euro") == 0) {
|
||||
checkError = 1;
|
||||
pDriv = CreateEURODriv(argc - 4, &argv[4]);
|
||||
@ -613,10 +573,6 @@ static pEVControl InstallPsiEnvironmentController(SicsInterp * pSics,
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int ConfigurePsiScan(pScanData self, char *option)
|
||||
{
|
||||
if (strcmp(option, "amor") == 0) {
|
||||
ConfigureAmor(self);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
971
tcpdocho.c
971
tcpdocho.c
@ -1,971 +0,0 @@
|
||||
/*--------------------------------------------------------------
|
||||
This is a driver for the newer Astrium == Dornier chopper
|
||||
systems which use a TCP/IP server for communication.
|
||||
This driver has to take care of some ugliness:
|
||||
- As of december 2005, the communication is in unicode!
|
||||
To go from ASCII to unicode and back one has to
|
||||
add a 0x00 before each character or to remove it.
|
||||
- The controller is slow in responding and the controller
|
||||
must be watched in the environment monitor. This is taken
|
||||
care of by a special SICS task which updates the status
|
||||
regularly and returning cached values anytime else.
|
||||
|
||||
|
||||
Inititial Implementation: Mark Koennecke, December 2005
|
||||
------------------------------------------------------------*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <fortify.h>
|
||||
#include <sics.h>
|
||||
#include <stringdict.h>
|
||||
#include <rs232controller.h>
|
||||
#include <codri.h>
|
||||
#include <stptok.h>
|
||||
#include <commandlog.h>
|
||||
/*========================================================================
|
||||
Our private data structure
|
||||
========================================================================*/
|
||||
#define ASYNMODE 0
|
||||
#define SYNCMODE 1
|
||||
|
||||
typedef struct {
|
||||
prs232 controller;
|
||||
int iRefreshIntervall;
|
||||
time_t nextRefresh;
|
||||
long lTask;
|
||||
pStringDict parameters;
|
||||
int lastError;
|
||||
int numChoppers;
|
||||
int mode;
|
||||
int timeout;
|
||||
char user[132];
|
||||
char pword[132];
|
||||
int stop;
|
||||
int busy;
|
||||
char *config;
|
||||
} TcpDoCho, *pTcpDoCho;
|
||||
/*-----------------------------------------------------------------------
|
||||
Error codes:
|
||||
-----------------------------------------------------------------------*/
|
||||
#define WRONGMODE -8301
|
||||
#define BADCONVERSION -8302
|
||||
#define FAILEDCOMMAND -8303
|
||||
#define BADWRITE -8304
|
||||
#define BADRESPONSE -8306
|
||||
#define UNDRIVABLE -8307
|
||||
#define BADPAR -8308
|
||||
#define ESTOP -8309
|
||||
|
||||
extern char *trim(char *str);
|
||||
#define ABS(x) (x < 0 ? -(x) : (x))
|
||||
|
||||
#define SPEEDTOL 2
|
||||
#define PHASETOL .5
|
||||
/*=============== support functions ===================================*/
|
||||
static int asciiToUnicode(char *input, char **output)
|
||||
{
|
||||
int len, i;
|
||||
char *result = NULL;
|
||||
|
||||
len = strlen(input);
|
||||
result = (char *) malloc(2 * len * sizeof(char));
|
||||
if (result == NULL) {
|
||||
return 0;
|
||||
}
|
||||
memset(result, 0, 2 * len * sizeof(char));
|
||||
for (i = 0; i < len; i++) {
|
||||
result[i * 2] = input[i];
|
||||
}
|
||||
*output = result;
|
||||
return 2 * len;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
static int unicodeToAscii(char *input, int len, char **output)
|
||||
{
|
||||
int i, alen;
|
||||
char *result = NULL;
|
||||
|
||||
alen = len / 2;
|
||||
|
||||
result = (char *) malloc((alen + 1) * sizeof(char));
|
||||
if (result == NULL) {
|
||||
return 0;
|
||||
}
|
||||
memset(result, 0, (alen + 1) * sizeof(char));
|
||||
for (i = 0; i < alen; i++) {
|
||||
result[i] = input[i * 2];
|
||||
}
|
||||
*output = result;
|
||||
return alen;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
static int tcpDoChoSend(pTcpDoCho self, char *command, int choNum,
|
||||
char *value)
|
||||
{
|
||||
char buffer[1024];
|
||||
int sendlen, status;
|
||||
|
||||
/*
|
||||
format and send command
|
||||
*/
|
||||
self->lastError = 0;
|
||||
if (choNum < 0) {
|
||||
snprintf(buffer, 1023, "#SOS#%s \r\n", command);
|
||||
} else if (value != NULL) {
|
||||
snprintf(buffer, 1023, "#SOS#%s%1.1d: %s\r\n", command, choNum, value);
|
||||
} else {
|
||||
snprintf(buffer, 1023, "#SOS#%s%1.1d:\r\n", command, choNum);
|
||||
}
|
||||
sendlen = strlen(buffer);
|
||||
if (sendlen == 0) {
|
||||
self->lastError = BADCONVERSION;
|
||||
return 0;
|
||||
}
|
||||
status = send(self->controller->pSock->sockid, buffer, sendlen, 0);
|
||||
if (status < 0) {
|
||||
self->lastError = BADWRITE;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
static int statusComplete(char *statusMessage)
|
||||
{
|
||||
char *pPtr = NULL;
|
||||
|
||||
/*
|
||||
currently the status message has no terminator. I try to find
|
||||
the last component of the message which happens to be TIME and
|
||||
the last # after that
|
||||
*/
|
||||
pPtr = strstr(statusMessage, "TIME");
|
||||
if (pPtr != NULL) {
|
||||
pPtr = strstr(pPtr + 6, "#");
|
||||
if (pPtr != NULL) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------*/
|
||||
static int readChopperNum(char *entry)
|
||||
{
|
||||
int num;
|
||||
char *pPtr = NULL;
|
||||
|
||||
pPtr = strstr(entry, "CH");
|
||||
if (pPtr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
sscanf(pPtr + 3, "%d", &num);
|
||||
return num;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------*/
|
||||
static void addEntry(pTcpDoCho self, int choNum, char *entry)
|
||||
{
|
||||
char name[80], value[80], *pPtr = NULL;
|
||||
char num[5];
|
||||
|
||||
memset(name, 0, 80);
|
||||
memset(value, 0, 80);
|
||||
snprintf(num, 5, "_%1.1d", choNum);
|
||||
pPtr = strstr(entry, "=");
|
||||
if (pPtr != NULL) {
|
||||
strncpy(name, entry, pPtr - entry);
|
||||
strncat(trim(name), num, 80 - strlen(trim(name)));
|
||||
strcpy(value, pPtr + 1);
|
||||
if (StringDictExists(self->parameters, name)) {
|
||||
StringDictUpdate(self->parameters, name, trim(value));
|
||||
} else {
|
||||
StringDictAddPair(self->parameters, name, trim(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
static int parseStatus(pTcpDoCho self, char *statusMessage)
|
||||
{
|
||||
int choNum;
|
||||
char entry[80], *pPtr;
|
||||
|
||||
pPtr = statusMessage;
|
||||
|
||||
/* skip over SOS */
|
||||
pPtr = stptok(pPtr, entry, 79, "#");
|
||||
pPtr = stptok(pPtr, entry, 79, "#");
|
||||
pPtr = stptok(pPtr, entry, 79, "#");
|
||||
|
||||
choNum = readChopperNum(entry);
|
||||
if (choNum < 0) {
|
||||
self->lastError = BADRESPONSE;
|
||||
return 0;
|
||||
}
|
||||
while ((pPtr = stptok(pPtr, entry, 79, "#")) != NULL) {
|
||||
addEntry(self, choNum, entry);
|
||||
memset(entry, 0, 80);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int tcpDoChoReceive(pTcpDoCho self)
|
||||
{
|
||||
char buffer[1024];
|
||||
int len, bytesRead, bufferStart, status;
|
||||
time_t endTime;
|
||||
|
||||
endTime = time(NULL) + self->timeout;
|
||||
bufferStart = 0;
|
||||
bytesRead = 0;
|
||||
memset(buffer, 0, 1024 * sizeof(char));
|
||||
while (time(NULL) < endTime) {
|
||||
if (availableRS232(self->controller)) {
|
||||
bytesRead +=
|
||||
recv(self->controller->pSock->sockid, buffer + bufferStart,
|
||||
1024 - bytesRead, 0);
|
||||
if (bytesRead < 0) {
|
||||
self->lastError = BADREAD;
|
||||
return 0;
|
||||
}
|
||||
if (strstr(buffer, "State") != NULL) {
|
||||
if (statusComplete(buffer) == 0) {
|
||||
continue;
|
||||
} else {
|
||||
status = parseStatus(self, buffer);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
if (strstr(buffer, "ACCEPT") != NULL) {
|
||||
return 1;
|
||||
} else if (strstr(buffer, "NCCEPT") != NULL) {
|
||||
self->lastError = FAILEDCOMMAND;
|
||||
return 0;
|
||||
} else {
|
||||
self->lastError = BADRESPONSE;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
SicsWait(1);
|
||||
}
|
||||
}
|
||||
self->lastError = TIMEOUT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int tcpDoChoCommand(pTcpDoCho self, char *command, int choNum,
|
||||
char *value)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = tcpDoChoSend(self, command, choNum, value);
|
||||
if (status == 0) {
|
||||
return 0;
|
||||
}
|
||||
return tcpDoChoReceive(self);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------*/
|
||||
static int TcpDoChoConnect(pTcpDoCho self)
|
||||
{
|
||||
int status, sendLen, readLen;
|
||||
char buffer[256];
|
||||
|
||||
status = initRS232(self->controller);
|
||||
if (status != 1) {
|
||||
self->lastError = status;
|
||||
return 0;
|
||||
}
|
||||
setRS232Timeout(self->controller, 5);
|
||||
|
||||
readLen = 255;
|
||||
readRS232(self->controller, (void *) buffer, &readLen);
|
||||
|
||||
/*
|
||||
user name
|
||||
*/
|
||||
snprintf(buffer, 255, "user:%s\r\n", self->user);
|
||||
sendLen = strlen(buffer);
|
||||
if (sendLen == 0) {
|
||||
self->lastError = BADCONVERSION;
|
||||
return 0;
|
||||
}
|
||||
status = send(self->controller->pSock->sockid, buffer, sendLen, 0);
|
||||
if (status < 0) {
|
||||
self->lastError = BADSEND;
|
||||
return 0;
|
||||
}
|
||||
readLen = 255;
|
||||
readRS232(self->controller, (void *) buffer, &readLen);
|
||||
|
||||
/*
|
||||
password
|
||||
*/
|
||||
snprintf(buffer, 255, "password:%s\r\n", self->pword);
|
||||
sendLen = strlen(buffer);
|
||||
if (sendLen == 0) {
|
||||
self->lastError = BADCONVERSION;
|
||||
return 0;
|
||||
}
|
||||
status = send(self->controller->pSock->sockid, buffer, sendLen, 0);
|
||||
if (status < 0) {
|
||||
self->lastError = BADSEND;
|
||||
return 0;
|
||||
}
|
||||
readLen = 255;
|
||||
readRS232(self->controller, (void *) buffer, &readLen);
|
||||
|
||||
/*
|
||||
TODO: responses should be checked to test for a valid login.
|
||||
I do not know at this time how the controller reacts upon a
|
||||
bad login.
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==================== actual driver implementation code ==================*/
|
||||
static int TcpChopperTask(void *pData)
|
||||
{
|
||||
pCodri self = NULL;
|
||||
pTcpDoCho pPriv = NULL;
|
||||
int status, code, i;
|
||||
char buffer[80];
|
||||
char error[512];
|
||||
|
||||
self = (pCodri) pData;
|
||||
assert(self);
|
||||
pPriv = (pTcpDoCho) self->pPrivate;
|
||||
assert(pPriv);
|
||||
|
||||
if (pPriv->stop == 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (time(NULL) > pPriv->nextRefresh) {
|
||||
if (pPriv->lastError != 0) {
|
||||
self->GetError(self, &code, buffer, 79);
|
||||
snprintf(error, 511, "WARNING: chopper tries to fix: %s", buffer);
|
||||
WriteToCommandLog("Chopper-task:>>", error);
|
||||
status = self->TryFixIt(self, code);
|
||||
if (status == CHFAIL) {
|
||||
pPriv->nextRefresh = time(NULL) + pPriv->iRefreshIntervall;
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
pPriv->busy = 1;
|
||||
for (i = 0; i < pPriv->numChoppers; i++) {
|
||||
status = tcpDoChoCommand(pPriv, "STATE ", i + 1, NULL);
|
||||
if (status != 1) {
|
||||
/*
|
||||
force error correction
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
pPriv->nextRefresh = time(NULL) + pPriv->iRefreshIntervall;
|
||||
pPriv->busy = 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
static int TcpDoChoKill(pCodri self)
|
||||
{
|
||||
pTcpDoCho pPriv = NULL;
|
||||
|
||||
pPriv = (pTcpDoCho) self->pPrivate;
|
||||
if (!pPriv)
|
||||
return 1;
|
||||
|
||||
if (pPriv->controller != NULL) {
|
||||
KillRS232(pPriv->controller);
|
||||
}
|
||||
if (pPriv->parameters != NULL) {
|
||||
DeleteStringDict(pPriv->parameters);
|
||||
}
|
||||
if (pPriv->config != NULL) {
|
||||
free(pPriv->config);
|
||||
}
|
||||
free(pPriv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
static int TcpDoChoConfigure(pCodri pDriv)
|
||||
{
|
||||
pTcpDoCho self = NULL;
|
||||
int status;
|
||||
char *pPtr = NULL;
|
||||
char command[80];
|
||||
|
||||
assert(pDriv != NULL);
|
||||
self = (pTcpDoCho) pDriv->pPrivate;
|
||||
assert(self != NULL);
|
||||
|
||||
if (self->config != NULL) {
|
||||
pPtr = self->config;
|
||||
while ((pPtr = stptok(pPtr, command, 79, "\n")) != NULL) {
|
||||
status = tcpDoChoCommand(self, command, -1, NULL);
|
||||
if (status != 1) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
static int TcpDoChoInit(pCodri pDriv)
|
||||
{
|
||||
pTcpDoCho self = NULL;
|
||||
int status;
|
||||
|
||||
assert(pDriv != NULL);
|
||||
self = (pTcpDoCho) pDriv->pPrivate;
|
||||
assert(self != NULL);
|
||||
|
||||
self->lastError = 0;
|
||||
self->stop = 0;
|
||||
self->nextRefresh = 0;
|
||||
|
||||
status = TcpDoChoConnect(self);
|
||||
if (status != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = TcpDoChoConfigure(pDriv);
|
||||
if (status != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* start the update task */
|
||||
if (self->lTask == 0) {
|
||||
self->lTask = TaskRegister(pServ->pTasker,
|
||||
TcpChopperTask, NULL, NULL, pDriv, 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
static void waitForBusy(pTcpDoCho self)
|
||||
{
|
||||
time_t endTime;
|
||||
|
||||
endTime = time(NULL) + 10 * 60; /* max 10 min */
|
||||
while (time(NULL) < endTime) {
|
||||
if (self->busy == 1) {
|
||||
SicsWait(3);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
WriteToCommandLog("Chopper-task>> ",
|
||||
"WARNING: timeout on busy flag, flag forced");
|
||||
self->busy = 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
static int TcpDoChoClose(pCodri pDriv)
|
||||
{
|
||||
pTcpDoCho self = NULL;
|
||||
int status;
|
||||
|
||||
assert(pDriv != NULL);
|
||||
self = (pTcpDoCho) pDriv->pPrivate;
|
||||
assert(self != NULL);
|
||||
|
||||
self->stop = 1;
|
||||
if (self->controller != NULL) {
|
||||
KillRS232(self->controller);
|
||||
self->controller = NULL;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
static int dissectName(char *name, char par[80], int *num)
|
||||
{
|
||||
char *pPtr = NULL;
|
||||
|
||||
pPtr = strrchr(name, (int) '_');
|
||||
if (pPtr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
memset(par, 0, 80 * sizeof(char));
|
||||
strncpy(par, name, pPtr - name);
|
||||
if (sscanf(pPtr + 1, "%d", num) != 1) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
static int TcpDoChoSetPar2(pCodri pDriv, char *parname, char *value)
|
||||
{
|
||||
|
||||
pTcpDoCho self = NULL;
|
||||
int status, choNum;
|
||||
char par[80], buffer[80], state[80];
|
||||
|
||||
assert(pDriv != NULL);
|
||||
self = (pTcpDoCho) pDriv->pPrivate;
|
||||
assert(self != NULL);
|
||||
|
||||
|
||||
/*
|
||||
force status requests right after setting something in order
|
||||
to make the stored status represent the new target values
|
||||
*/
|
||||
if (dissectName(parname, par, &choNum)) {
|
||||
/*
|
||||
check for emergency stop
|
||||
*/
|
||||
snprintf(buffer, 79, "State_%1.1d", choNum);
|
||||
memset(state, 0, 80 * sizeof(char));
|
||||
StringDictGet(self->parameters, buffer, state, 79);
|
||||
if (strstr(state, "E-Stop") != NULL) {
|
||||
self->lastError = ESTOP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(par, "speed") == 0) {
|
||||
waitForBusy(self);
|
||||
status = tcpDoChoCommand(self, "SPEED ", choNum, trim(value));
|
||||
tcpDoChoCommand(self, "STATE ", choNum, NULL);
|
||||
if (status != 1) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
} else if (strcmp(par, "phase") == 0) {
|
||||
waitForBusy(self);
|
||||
status = tcpDoChoCommand(self, "PHASE ", choNum, trim(value));
|
||||
tcpDoChoCommand(self, "STATE ", choNum, NULL);
|
||||
if (status != 1) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
self->lastError = UNDRIVABLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static int TcpDoChoHalt(pCodri pDriv)
|
||||
{
|
||||
|
||||
pTcpDoCho self = NULL;
|
||||
int status;
|
||||
|
||||
assert(pDriv != NULL);
|
||||
self = (pTcpDoCho) pDriv->pPrivate;
|
||||
assert(self != NULL);
|
||||
|
||||
waitForBusy(self);
|
||||
tcpDoChoCommand(self, "ESTOP :", -1, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static int TcpDoChoSetPar(pCodri pDriv, char *parname, float fValue)
|
||||
{
|
||||
|
||||
pTcpDoCho self = NULL;
|
||||
int status, choNum;
|
||||
char value[80];
|
||||
char par[80];
|
||||
|
||||
|
||||
assert(pDriv != NULL);
|
||||
self = (pTcpDoCho) pDriv->pPrivate;
|
||||
assert(self != NULL);
|
||||
|
||||
if (dissectName(parname, par, &choNum)) {
|
||||
if (strcmp(par, "speed") == 0) {
|
||||
snprintf(value, 79, "%5.1f", fValue);
|
||||
return TcpDoChoSetPar2(pDriv, parname, value);
|
||||
} else if (strcmp(par, "phase") == 0) {
|
||||
snprintf(value, 79, "%6.2f", fValue);
|
||||
return TcpDoChoSetPar2(pDriv, parname, value);
|
||||
}
|
||||
}
|
||||
if (strcmp(parname, "updateintervall") == 0) {
|
||||
sprintf(value, "%d", (int) fValue);
|
||||
StringDictUpdate(self->parameters, "updateintervall", value);
|
||||
self->iRefreshIntervall = (int) fValue;
|
||||
return 1;
|
||||
} else {
|
||||
snprintf(value, 79, "%f", fValue);
|
||||
return TcpDoChoSetPar2(pDriv, parname, value);
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
static int TcpDoChoGetPar(pCodri pDriv, char *parname,
|
||||
char *pBuffer, int iBuflen)
|
||||
{
|
||||
pTcpDoCho self = NULL;
|
||||
int status = 0, choNum;
|
||||
char par[80], buffer[80];
|
||||
float val;
|
||||
|
||||
assert(pDriv != NULL);
|
||||
self = (pTcpDoCho) pDriv->pPrivate;
|
||||
assert(self != NULL);
|
||||
|
||||
memset(par, 0, 80);
|
||||
dissectName(parname, par, &choNum);
|
||||
if (strcmp(par, "speed") == 0) {
|
||||
snprintf(buffer, 80, "ASPEED_%1.1d", choNum);
|
||||
status = StringDictGet(self->parameters, buffer, pBuffer, iBuflen);
|
||||
} else if (strcmp(par, "phase") == 0) {
|
||||
snprintf(buffer, 80, "APHASE_%1.1d", choNum);
|
||||
status = StringDictGet(self->parameters, buffer, pBuffer, iBuflen);
|
||||
} else {
|
||||
status = StringDictGet(self->parameters, parname, pBuffer, iBuflen);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
static int TcpDoChoCheckPar(pCodri pDriv, char *parname)
|
||||
{
|
||||
pTcpDoCho self = NULL;
|
||||
int status = 0, choNum;
|
||||
float val, soll, delta;
|
||||
char value[80], csoll[80], par[80], buffer[80], state[80];
|
||||
|
||||
assert(pDriv != NULL);
|
||||
self = (pTcpDoCho) pDriv->pPrivate;
|
||||
assert(self != NULL);
|
||||
|
||||
/*
|
||||
check for flags first
|
||||
*/
|
||||
if (self->busy) {
|
||||
return HWBusy;
|
||||
}
|
||||
if (self->lastError != 0) {
|
||||
return HWFault;
|
||||
}
|
||||
|
||||
/*
|
||||
updateintervall is always Idle
|
||||
*/
|
||||
if (strcmp(parname, "updateintervall") == 0) {
|
||||
return HWIdle;
|
||||
}
|
||||
|
||||
/*
|
||||
check for emergency stop
|
||||
*/
|
||||
snprintf(buffer, 79, "State_%1.1d", choNum);
|
||||
memset(state, 0, 80 * sizeof(char));
|
||||
StringDictGet(self->parameters, buffer, state, 79);
|
||||
if (strstr(state, "E-Stop") != NULL) {
|
||||
self->lastError = HWFault;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(par, 0, 80);
|
||||
dissectName(parname, par, &choNum);
|
||||
if (strcmp(par, "speed") == 0) {
|
||||
snprintf(buffer, 79, "RSPEED_%1.1d", choNum);
|
||||
StringDictGet(self->parameters, buffer, csoll, 79);
|
||||
sscanf(csoll, "%f", &soll);
|
||||
snprintf(buffer, 79, "ASPEED_%1.1d", choNum);
|
||||
StringDictGet(self->parameters, buffer, value, 79);
|
||||
sscanf(value, "%f", &val);
|
||||
delta = ABS(soll - val);
|
||||
if (delta > SPEEDTOL) {
|
||||
return HWBusy;
|
||||
} else {
|
||||
return HWIdle;
|
||||
}
|
||||
} else if (strcmp(par, "phase") == 0) {
|
||||
snprintf(buffer, 79, "RPHASE_%1.1d", choNum);
|
||||
StringDictGet(self->parameters, buffer, csoll, 79);
|
||||
sscanf(value, "%f", &soll);
|
||||
snprintf(buffer, 79, "APHASE_%1.1d", choNum);
|
||||
StringDictGet(self->parameters, buffer, value, 79);
|
||||
sscanf(value, "%f", &val);
|
||||
delta = ABS(soll - val);
|
||||
if (delta > PHASETOL) {
|
||||
return HWBusy;
|
||||
} else {
|
||||
return HWIdle;
|
||||
}
|
||||
}
|
||||
self->lastError = BADPAR;
|
||||
return HWFault;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int TcpDoChoError(pCodri pDriv, int *iCode, char *pError, int iLen)
|
||||
{
|
||||
pTcpDoCho self = NULL;
|
||||
int status = 0;
|
||||
float val, soll, delta;
|
||||
char value[80];
|
||||
|
||||
assert(pDriv != NULL);
|
||||
self = (pTcpDoCho) pDriv->pPrivate;
|
||||
assert(self != NULL);
|
||||
|
||||
*iCode = self->lastError;
|
||||
switch (self->lastError) {
|
||||
case WRONGMODE:
|
||||
strncpy(pError, "Chopper in wrong mode", iLen);
|
||||
break;
|
||||
case BADCONVERSION:
|
||||
strncpy(pError, "Bad ASCII to unicode conversion", iLen);
|
||||
break;
|
||||
case FAILEDCOMMAND:
|
||||
strncpy(pError, "Command not accepted", iLen);
|
||||
break;
|
||||
case BADWRITE:
|
||||
strncpy(pError, "Failed to write to chopper controller", iLen);
|
||||
break;
|
||||
case BADRESPONSE:
|
||||
strncpy(pError, "Chopper controller send invalid command", iLen);
|
||||
break;
|
||||
case UNDRIVABLE:
|
||||
strncpy(pError, "Parameter cannot be changed", iLen);
|
||||
break;
|
||||
case BADPAR:
|
||||
strncpy(pError, "No such parameter", iLen);
|
||||
break;
|
||||
case ESTOP:
|
||||
strncpy(pError, "Emergency stop is engaged", iLen);
|
||||
break;
|
||||
default:
|
||||
getRS232Error(self->lastError, pError, iLen);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
static int TcpDoChoFix(pCodri pDriv, int iCode)
|
||||
{
|
||||
pTcpDoCho self = NULL;
|
||||
int status = 0;
|
||||
float val, soll, delta;
|
||||
char value[80];
|
||||
|
||||
assert(pDriv != NULL);
|
||||
self = (pTcpDoCho) pDriv->pPrivate;
|
||||
assert(self != NULL);
|
||||
|
||||
self->lastError = 0;
|
||||
switch (iCode) {
|
||||
case BADCONVERSION:
|
||||
case BADRESPONSE:
|
||||
return CHREDO;
|
||||
break;
|
||||
case WRONGMODE:
|
||||
case FAILEDCOMMAND:
|
||||
case UNDRIVABLE:
|
||||
case BADPAR:
|
||||
case ESTOP:
|
||||
return CHFAIL;
|
||||
break;
|
||||
default:
|
||||
closeRS232(self->controller);
|
||||
status = TcpDoChoConnect(self);
|
||||
if (status == 1) {
|
||||
return CHREDO;
|
||||
} else {
|
||||
return CHFAIL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return CHFAIL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
pCodri MakeTcpDoChoDriver(char *tclArray, SConnection * pCon)
|
||||
{
|
||||
pCodri pNew = NULL;
|
||||
pTcpDoCho self = NULL;
|
||||
const char *pPtr = NULL;
|
||||
char buffer[132];
|
||||
int port, i, count;
|
||||
Tcl_DString pars;
|
||||
char *parnames[] = { "State",
|
||||
"ASPEED",
|
||||
"RSPEED",
|
||||
"APHASE",
|
||||
"RPHASE",
|
||||
"AVETO",
|
||||
"DIR",
|
||||
"MONIT",
|
||||
"FLOWR",
|
||||
"WTEMP",
|
||||
"MTEMP",
|
||||
"MVIBR",
|
||||
"MVACU",
|
||||
"speed",
|
||||
"phase",
|
||||
NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
allocate memory
|
||||
*/
|
||||
pNew = (pCodri) malloc(sizeof(Codri));
|
||||
self = (pTcpDoCho) malloc(sizeof(TcpDoCho));
|
||||
if (!pNew || !self) {
|
||||
return NULL;
|
||||
}
|
||||
memset(pNew, 0, sizeof(Codri));
|
||||
memset(self, 0, sizeof(TcpDoCho));
|
||||
|
||||
/* port and host name */
|
||||
pPtr =
|
||||
Tcl_GetVar2(pServ->pSics->pTcl, tclArray, "port", TCL_GLOBAL_ONLY);
|
||||
if (!pPtr) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: port not found in configuration array for TCP Dornier Chopper",
|
||||
eError);
|
||||
free(pNew);
|
||||
free(self);
|
||||
return NULL;
|
||||
}
|
||||
sscanf(pPtr, "%d", &port);
|
||||
pPtr =
|
||||
Tcl_GetVar2(pServ->pSics->pTcl, tclArray, "host", TCL_GLOBAL_ONLY);
|
||||
if (!pPtr) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: host not found in configuration array for TCP Dornier Chopper",
|
||||
eError);
|
||||
free(pNew);
|
||||
free(self);
|
||||
return NULL;
|
||||
}
|
||||
memset(buffer, 0, 132);
|
||||
strncpy(buffer, pPtr, 131);
|
||||
self->controller = createRS232(buffer, port);
|
||||
|
||||
/* number of choppers */
|
||||
pPtr =
|
||||
Tcl_GetVar2(pServ->pSics->pTcl, tclArray, "nchopper",
|
||||
TCL_GLOBAL_ONLY);
|
||||
if (!pPtr) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: nchopper not found in configuration array for TCP Dornier Chopper",
|
||||
eError);
|
||||
free(pNew);
|
||||
free(self);
|
||||
return NULL;
|
||||
}
|
||||
sscanf(pPtr, "%d", &port);
|
||||
if (port < 0 || port > 8) {
|
||||
SCWrite(pCon, "ERROR: number of choppers not in range 1 - 8", eError);
|
||||
free(pNew);
|
||||
free(self);
|
||||
}
|
||||
self->numChoppers = port;
|
||||
|
||||
/* timeout */
|
||||
pPtr =
|
||||
Tcl_GetVar2(pServ->pSics->pTcl, tclArray, "timeout",
|
||||
TCL_GLOBAL_ONLY);
|
||||
if (!pPtr) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: timeout not found in configuration array for TCP Dornier Chopper",
|
||||
eError);
|
||||
free(pNew);
|
||||
free(self);
|
||||
return NULL;
|
||||
}
|
||||
sscanf(pPtr, "%d", &port);
|
||||
self->timeout = port;
|
||||
|
||||
/* username and password */
|
||||
pPtr =
|
||||
Tcl_GetVar2(pServ->pSics->pTcl, tclArray, "user", TCL_GLOBAL_ONLY);
|
||||
if (!pPtr) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: user not found in configuration array for TCP Dornier Chopper",
|
||||
eError);
|
||||
free(pNew);
|
||||
free(self);
|
||||
return NULL;
|
||||
}
|
||||
strncpy(self->user, pPtr, 131);
|
||||
pPtr =
|
||||
Tcl_GetVar2(pServ->pSics->pTcl, tclArray, "password",
|
||||
TCL_GLOBAL_ONLY);
|
||||
if (!pPtr) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: password not found in configuration array for TCP Dornier Chopper",
|
||||
eError);
|
||||
free(pNew);
|
||||
free(self);
|
||||
return NULL;
|
||||
}
|
||||
strncpy(self->pword, pPtr, 131);
|
||||
|
||||
/*
|
||||
chopper configuration
|
||||
*/
|
||||
pPtr =
|
||||
Tcl_GetVar2(pServ->pSics->pTcl, tclArray, "config", TCL_GLOBAL_ONLY);
|
||||
if (pPtr != NULL) {
|
||||
self->config = strdup(pPtr);
|
||||
}
|
||||
|
||||
|
||||
/* initialize some more */
|
||||
self->parameters = CreateStringDict();
|
||||
if (self->parameters == NULL || self->controller == NULL) {
|
||||
SCWrite(pCon, "ERROR: out of memory in MakeTcpDoCho", eError);
|
||||
free(pNew);
|
||||
free(self);
|
||||
return NULL;
|
||||
}
|
||||
self->iRefreshIntervall = 60;
|
||||
pNew->Init = TcpDoChoInit;
|
||||
pNew->Close = TcpDoChoClose;
|
||||
pNew->Delete = TcpDoChoKill;
|
||||
pNew->SetPar = TcpDoChoSetPar;
|
||||
pNew->SetPar2 = TcpDoChoSetPar2;
|
||||
pNew->GetPar = TcpDoChoGetPar;
|
||||
pNew->CheckPar = TcpDoChoCheckPar;
|
||||
pNew->GetError = TcpDoChoError;
|
||||
pNew->TryFixIt = TcpDoChoFix;
|
||||
pNew->Halt = TcpDoChoHalt;
|
||||
StringDictAddPair(self->parameters, "updateintervall", "60");
|
||||
pNew->pPrivate = self;
|
||||
|
||||
/*
|
||||
create parameter list
|
||||
*/
|
||||
Tcl_DStringInit(&pars);
|
||||
count = 0;
|
||||
Tcl_DStringAppend(&pars, "updateintervall", 15);
|
||||
while (parnames[count] != NULL) {
|
||||
for (i = 0; i < self->numChoppers; i++) {
|
||||
snprintf(buffer, 131, ",%s_%1.1d", parnames[count], i + 1);
|
||||
Tcl_DStringAppend(&pars, buffer, strlen(buffer));
|
||||
}
|
||||
count++;
|
||||
}
|
||||
pNew->pParList = strdup(Tcl_DStringValue(&pars));
|
||||
Tcl_DStringFree(&pars);
|
||||
return pNew;
|
||||
}
|
1169
tcpdornier.c
1169
tcpdornier.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user