- SICS cleanup: removed unused code
SKIPPED: psi/make_gen psi/makefile_linux psi/polterwrite.c psi/psi.c
This commit is contained in:
114
cryst.c
114
cryst.c
@ -1,114 +0,0 @@
|
||||
/*---------------------------------------------------------------------------
|
||||
C r y s t
|
||||
|
||||
This is a library of crystallographic utility routines for four
|
||||
circle diffractometers. It deals with all sorts of rotations and
|
||||
stuff. This is based on code originally developed by John Allibon
|
||||
at ILL and reimplemented in C using a matrix-library.
|
||||
|
||||
Mark Koennecke, July 2000
|
||||
----------------------------------------------------------------------------*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include "matrix/matrix.h"
|
||||
#include "cryst.h"
|
||||
|
||||
#define PIR 57.30
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
chimat, calculate chi rotation matrix. The input angle is in degrees.
|
||||
The setting is Busing & Levy.
|
||||
--------------------------------------------------------------------------*/
|
||||
|
||||
MATRIX chimat(double dAngle)
|
||||
{
|
||||
MATRIX res;
|
||||
double dChi;
|
||||
|
||||
res = mat_creat(3, 3, ZERO_MATRIX);
|
||||
dChi = dAngle / PIR;
|
||||
|
||||
res[0][0] = cos(dChi);
|
||||
res[0][2] = sin(dChi);
|
||||
res[1][1] = 1.;
|
||||
res[2][0] = -res[0][2];
|
||||
res[2][2] = res[0][0];
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
phimat, calculate phi rotation matrix. The input angle is in degrees.
|
||||
The setting is Busing & Levy.
|
||||
--------------------------------------------------------------------------*/
|
||||
|
||||
MATRIX phimat(double dAngle)
|
||||
{
|
||||
MATRIX res;
|
||||
double dPhi;
|
||||
|
||||
res = mat_creat(3, 3, ZERO_MATRIX);
|
||||
dPhi = dAngle / PIR;
|
||||
|
||||
res[0][0] = cos(dPhi);
|
||||
res[0][1] = sin(dChi);
|
||||
res[2][2] = 1.;
|
||||
res[1][0] = -res[0][1];
|
||||
res[1][1] = res[0][0];
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
psimat, calculate psi rotation matrix. The input angle is in degrees.
|
||||
The setting is Busing & Levy.
|
||||
--------------------------------------------------------------------------*/
|
||||
|
||||
MATRIX psimat(double dAngle)
|
||||
{
|
||||
MATRIX res;
|
||||
double dPsi;
|
||||
|
||||
res = mat_creat(3, 3, ZERO_MATRIX);
|
||||
dPsi = dAngle / PIR;
|
||||
|
||||
res[0][0] = 1.;
|
||||
res[1][1] = cos(dPsi);
|
||||
res[1][2] = -sin(dPsi);
|
||||
res[2][1] = -res[1][2];
|
||||
res[2][2] = res[1][1];
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
diffFromAngles calculates the diffraction vector from two theta, omega
|
||||
chi and phi. The angled need not be bissecting but it is assumed that
|
||||
the diffraction vector is in the equatorial plane.
|
||||
--------------------------------------------------------------------------*/
|
||||
|
||||
MATRIX diffFromAngles(double wave, double tth, double om,
|
||||
double chi, double phi)
|
||||
{
|
||||
MATRIX res, rot, dum, z;
|
||||
double dTh;
|
||||
|
||||
dTh = (tth / 2.) / PIR;
|
||||
res = mat_creat(3, 1, ZERO_MATRIX);
|
||||
res[0][0] = (2. * sin(dTh) * cos(dTh)) / wave;
|
||||
res[1][0] = (-2. * sin(dTh) * sin(dTh)) / wave;
|
||||
|
||||
/* undo omega rotation */
|
||||
rot = phimat(om);
|
||||
dum = mat_tran(rot);
|
||||
mat_free(rot);
|
||||
z = mat_mul(dum, res);
|
||||
mat_free(dum);
|
||||
mat_free(res);
|
||||
|
||||
/* result is now z */
|
||||
|
||||
}
|
@ -1,642 +0,0 @@
|
||||
/**
|
||||
* This is a generic controller for devices in SICS. It is configurable via Tcl
|
||||
* scripts.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, November 2007
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <tcl.h>
|
||||
#include <sics.h>
|
||||
#include <macro.h>
|
||||
#include <sicshipadaba.h>
|
||||
#include <sicsobj.h>
|
||||
#include <dynstring.h>
|
||||
#include <genericcontroller.h>
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static hdbCallbackReturn GenConSetCallback(pHdb node, void *userData,
|
||||
pHdbMessage message)
|
||||
{
|
||||
pSICSOBJ self = (pSICSOBJ) userData;
|
||||
SConnection *pCon = NULL;
|
||||
pGenController priv = NULL;
|
||||
char command[1024];
|
||||
char value[80];
|
||||
int status, privilege;
|
||||
pDynString data;
|
||||
pHdbDataMessage mm = NULL;
|
||||
|
||||
assert(self != NULL);
|
||||
|
||||
if ((mm = GetHdbSetMessage(message)) == NULL) {
|
||||
return hdbContinue;
|
||||
}
|
||||
|
||||
priv = (pGenController) self->pPrivate;
|
||||
pCon = mm->callData;
|
||||
|
||||
/*
|
||||
* check rights
|
||||
*/
|
||||
memset(value, 0, 80);
|
||||
if (GetHdbProperty(node, "priv", value, 80) && pCon != NULL) {
|
||||
privilege = usInternal;
|
||||
if (strcmp(value, "manager") == 0) {
|
||||
privilege = usMugger;
|
||||
}
|
||||
if (strcmp(value, "user") == 0) {
|
||||
privilege = usUser;
|
||||
}
|
||||
if (!SCMatchRights(pCon, privilege)) {
|
||||
return hdbAbort;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* check writeCommand
|
||||
*/
|
||||
memset(value, 0, 80);
|
||||
GetHdbProperty(node, "writeCommand", value, 80);
|
||||
if (strlen(value) < 2) {
|
||||
if (pCon != NULL) {
|
||||
SCWrite(pCon, "ERROR: parameter is read-only", eError);
|
||||
return hdbAbort;
|
||||
}
|
||||
return hdbAbort;
|
||||
}
|
||||
|
||||
/*
|
||||
* check status
|
||||
*/
|
||||
memset(value, 0, 80);
|
||||
GetHdbProperty(node, "status", value, 80);
|
||||
if (strstr(value, "idle") == NULL) {
|
||||
return hdbAbort;
|
||||
}
|
||||
SetHdbProperty(node, "status", "setting");
|
||||
data = formatValue(*(mm->v), node);
|
||||
if (data != NULL) {
|
||||
SetHdbProperty(node, "target", GetCharArray(data));
|
||||
DeleteDynString(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* issue command
|
||||
*/
|
||||
if (priv->enqueueNodeHead != NULL) {
|
||||
priv->enqueueNodeHead(self, pCon, node);
|
||||
} else {
|
||||
if (pCon != NULL) {
|
||||
SCWrite(pCon, "ERROR: generic controller NOT configured", eError);
|
||||
}
|
||||
return hdbAbort;
|
||||
}
|
||||
|
||||
return hdbContinue;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static hdbCallbackReturn GenConGetCallback(pHdb node, void *userData,
|
||||
pHdbMessage message)
|
||||
{
|
||||
pSICSOBJ self = (pSICSOBJ) userData;
|
||||
SConnection *pCon = NULL;
|
||||
pGenController priv = NULL;
|
||||
char command[1024];
|
||||
char value[256];
|
||||
int status, privilege;
|
||||
pHdbDataMessage mm = NULL;
|
||||
|
||||
assert(self != NULL);
|
||||
|
||||
if ((mm = GetHdbGetMessage(message)) == NULL) {
|
||||
return hdbContinue;
|
||||
}
|
||||
pCon = mm->callData;
|
||||
|
||||
priv = (pGenController) self->pPrivate;
|
||||
|
||||
/*
|
||||
* check status
|
||||
*/
|
||||
memset(value, 0, 80);
|
||||
GetHdbProperty(node, "status", value, 80);
|
||||
if (strstr(value, "idle") == NULL) {
|
||||
return hdbContinue;
|
||||
}
|
||||
SetHdbProperty(node, "status", "getting");
|
||||
|
||||
/*
|
||||
* check readCommand
|
||||
*/
|
||||
memset(value, 0, 256);
|
||||
GetHdbProperty(node, "readCommand", value, 255);
|
||||
if (strlen(value) < 2) {
|
||||
return hdbAbort;
|
||||
} else {
|
||||
if (priv->enqueueNode != NULL) {
|
||||
priv->enqueueNode(self, pCon, node);
|
||||
} else {
|
||||
if (pCon != NULL) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: generic controller connection NOT configured",
|
||||
eError);
|
||||
}
|
||||
return hdbAbort;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Upper Level GetHipadabaPar will automatically return the
|
||||
* node value. Which should have been updated through an update
|
||||
* during the execution of enqueueNode
|
||||
*/
|
||||
|
||||
return hdbContinue;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static pHdb MakeGenConPar(pSICSOBJ self, char *name, int type, int length)
|
||||
{
|
||||
pHdb result = NULL;
|
||||
pHdbCallback kalle = NULL;
|
||||
|
||||
result = MakeHipadabaNode(name, type, length);
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kalle = MakeHipadabaCallback(GenConSetCallback, self, NULL);
|
||||
if (kalle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
AppendHipadabaCallback(result, kalle);
|
||||
|
||||
kalle = MakeHipadabaCallback(GenConGetCallback, self, NULL);
|
||||
|
||||
if (kalle == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
AppendHipadabaCallback(result, kalle);
|
||||
|
||||
SetHdbProperty(result, "priv", "manager");
|
||||
SetHdbProperty(result, "readCommand", "");
|
||||
SetHdbProperty(result, "writeCommand", "");
|
||||
SetHdbProperty(result, "replyCommand", "");
|
||||
SetHdbProperty(result, "status", "idle");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int MakeGenPar(pSICSOBJ self, SConnection * pCon,
|
||||
char *argv[], int argc)
|
||||
{
|
||||
char buffer[2048];
|
||||
int type, length = 1;
|
||||
pHdb node = NULL, parent;
|
||||
char *pPtr = NULL;
|
||||
|
||||
if (argc < 5) {
|
||||
snprintf(buffer, 2048, "ERROR: insufficient arguments to %s makepar",
|
||||
argv[0]);
|
||||
SCWrite(pCon, buffer, eError);
|
||||
return 0;
|
||||
}
|
||||
type = convertHdbType(argv[4]);
|
||||
if (argc > 5) {
|
||||
length = atoi(argv[5]);
|
||||
}
|
||||
strncpy(buffer, argv[3], 2047);
|
||||
pPtr = strrchr(buffer, '/');
|
||||
if (pPtr == NULL) {
|
||||
node = MakeGenConPar(self, argv[3], type, length);
|
||||
parent = self->objectNode;
|
||||
} else {
|
||||
*pPtr = '\0';
|
||||
pPtr++;
|
||||
node = MakeGenConPar(self, pPtr, type, length);
|
||||
parent = GetHipadabaNode(self->objectNode, buffer);
|
||||
}
|
||||
if (node == NULL || parent == NULL) {
|
||||
SCWrite(pCon, "ERROR: failed to create node or parent not found",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
AddHipadabaChild(parent, node, pCon);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*=============================== ==========================================
|
||||
* This stuff is for the Tcl - AsynQueue implementation of GenericController
|
||||
* ==========================================================================*/
|
||||
typedef struct {
|
||||
pHdb node;
|
||||
pSICSOBJ obj;
|
||||
SConnection *pCon;
|
||||
pGenController priv;
|
||||
pAsyncUnit assi;
|
||||
pAsyncTxn trans;
|
||||
char replyCommand[2048];
|
||||
} GenContext, *pGenContext;
|
||||
/*--------------------------------------------------------------------------
|
||||
* This is called by AsyncQueue when a reply has been received.
|
||||
* -------------------------------------------------------------------------*/
|
||||
static int GenConTxnHandler(pAsyncTxn pTxn)
|
||||
{
|
||||
pGenContext genCon = NULL;
|
||||
char reply[10240];
|
||||
|
||||
genCon = (pGenContext) pTxn->cntx;
|
||||
assert(genCon != NULL);
|
||||
|
||||
memset(reply, 0, 10240 * sizeof(char));
|
||||
switch (pTxn->txn_state) {
|
||||
case ATX_NULL:
|
||||
case ATX_ACTIVE:
|
||||
return 1;
|
||||
break;
|
||||
case ATX_TIMEOUT:
|
||||
strcpy(reply, "TIMEOUT");
|
||||
break;
|
||||
case ATX_DISCO:
|
||||
strcpy(reply, "DISCONNECTED");
|
||||
break;
|
||||
case ATX_COMPLETE:
|
||||
strncpy(reply, pTxn->inp_buf, 10240);
|
||||
break;
|
||||
}
|
||||
|
||||
genCon->priv->replyCallback(genCon->obj, genCon->pCon,
|
||||
genCon->node, genCon->replyCommand, reply,
|
||||
strlen(reply));
|
||||
if (genCon->pCon != NULL) {
|
||||
SCDeleteConnection(genCon->pCon);
|
||||
}
|
||||
free(genCon);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static char *formatCommand(pHdb node, SConnection * pCon)
|
||||
{
|
||||
pDynString com = NULL;
|
||||
char value[512];
|
||||
Tcl_Interp *pTcl = NULL;
|
||||
int status;
|
||||
|
||||
com = CreateDynString(256, 128);
|
||||
if (com == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(value, 0, 512);
|
||||
GetHdbProperty(node, "status", value, 512);
|
||||
if (strstr(value, "set") != NULL) {
|
||||
memset(value, 0, 512);
|
||||
GetHdbProperty(node, "writeCommand", value, 512);
|
||||
DynStringConcat(com, value);
|
||||
DynStringConcatChar(com, ' ');
|
||||
memset(value, 0, 512);
|
||||
GetHdbProperty(node, "target", value, 512);
|
||||
DynStringConcat(com, value);
|
||||
} else {
|
||||
memset(value, 0, 512);
|
||||
GetHdbProperty(node, "readCommand", value, 512);
|
||||
DynStringConcat(com, value);
|
||||
}
|
||||
pTcl = InterpGetTcl(pServ->pSics);
|
||||
if (pCon != NULL) {
|
||||
MacroPush(pCon);
|
||||
}
|
||||
status = Tcl_Eval(pTcl, GetCharArray(com));
|
||||
if (pCon != NULL) {
|
||||
MacroPop();
|
||||
}
|
||||
DeleteDynString(com);
|
||||
if (status != TCL_OK) {
|
||||
SetHdbProperty(node, "result", (char *) Tcl_GetStringResult(pTcl));
|
||||
return NULL;
|
||||
}
|
||||
return strdup(Tcl_GetStringResult(pTcl));
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static pGenContext PrepareToEnque(pSICSOBJ self, SConnection * pCon,
|
||||
pHdb node)
|
||||
{
|
||||
pGenContext result = NULL;
|
||||
char *command = NULL;
|
||||
pGenController priv = NULL;
|
||||
|
||||
priv = (pGenController) self->pPrivate;
|
||||
assert(priv != NULL);
|
||||
|
||||
command = formatCommand(node, pCon);
|
||||
if (command == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = malloc(sizeof(GenContext));
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset(result, 0, sizeof(GenContext));
|
||||
if (!GetHdbProperty(node, "replyCommand", result->replyCommand, 2048)) {
|
||||
if (pCon != NULL) {
|
||||
SCWrite(pCon, "ERROR: no replyCommand found", eError);
|
||||
}
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result->assi = AsyncUnitFromQueue((pAsyncQueue) priv->comContext);
|
||||
if (result->assi == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
result->trans = AsyncUnitPrepareTxn(result->assi,
|
||||
command, strlen(command),
|
||||
GenConTxnHandler, result, 2048);
|
||||
if (result->trans == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
result->node = node;
|
||||
result->priv = priv;
|
||||
result->obj = self;
|
||||
result->pCon = SCCopyConnection(pCon);
|
||||
priv->comError = GCOK;
|
||||
free(command);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int AsyncEnqueueNode(pSICSOBJ self, SConnection * pCon, pHdb node)
|
||||
{
|
||||
pGenContext genCon = NULL;
|
||||
|
||||
genCon = PrepareToEnque(self, pCon, node);
|
||||
if (genCon == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return AsyncUnitEnqueueTxn(genCon->assi, genCon->trans);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int AsyncEnqueueNodeHead(pSICSOBJ self, SConnection * pCon,
|
||||
pHdb node)
|
||||
{
|
||||
pGenContext genCon = NULL;
|
||||
|
||||
genCon = PrepareToEnque(self, pCon, node);
|
||||
if (genCon == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return AsyncUnitEnqueueHead(genCon->assi, genCon->trans);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int AsyncReply(pSICSOBJ self, SConnection * pCon, pHdb node,
|
||||
char *replyCommand, char *reply, int replylen)
|
||||
{
|
||||
pDynString com = NULL;
|
||||
Tcl_Interp *pTcl;
|
||||
int status;
|
||||
|
||||
SetHdbProperty(node, "result", reply);
|
||||
|
||||
com = CreateDynString(256, 128);
|
||||
if (com == NULL) {
|
||||
return 0;
|
||||
}
|
||||
DynStringConcat(com, replyCommand);
|
||||
DynStringConcat(com, " \"");
|
||||
DynStringConcat(com, reply);
|
||||
DynStringConcat(com, "\"\0");
|
||||
if (pCon != NULL) {
|
||||
MacroPush(pCon);
|
||||
}
|
||||
pTcl = InterpGetTcl(pServ->pSics);
|
||||
status = Tcl_Eval(pTcl, GetCharArray(com));
|
||||
if (pCon != NULL) {
|
||||
MacroPop();
|
||||
}
|
||||
DeleteDynString(com);
|
||||
if (status != TCL_OK) {
|
||||
SetHdbProperty(node, "lastError", (char *) Tcl_GetStringResult(pTcl));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/*============= GenController Object Functions ==============================*/
|
||||
static int ConnectAsync(pSICSOBJ self, SConnection * pCon,
|
||||
char *argv[], int argc)
|
||||
{
|
||||
pGenController priv = NULL;
|
||||
pAsyncQueue assi = NULL;
|
||||
char buffer[2048];
|
||||
pAsyncUnit uni = NULL;
|
||||
|
||||
priv = (pGenController) self->pPrivate;
|
||||
assert(priv != NULL);
|
||||
|
||||
if (argc < 4) {
|
||||
snprintf(buffer, 2048,
|
||||
"ERROR: insufficient arguments to %s asynconnect", argv[0]);
|
||||
SCWrite(pCon, buffer, eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
assi =
|
||||
(pAsyncQueue) FindCommandData(pServ->pSics, argv[3], "AsyncQueue");
|
||||
if (assi == NULL) {
|
||||
snprintf(buffer, 2048, "ERROR: %s not found or no AsyncQueue",
|
||||
argv[3]);
|
||||
SCWrite(pCon, buffer, eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
priv->comContext = assi;
|
||||
priv->killComContext = NULL; /* not ours, cleaned up by AsyncQueue module */
|
||||
priv->enqueueNode = AsyncEnqueueNode;
|
||||
priv->enqueueNodeHead = AsyncEnqueueNodeHead;
|
||||
priv->replyCallback = AsyncReply;
|
||||
priv->comError = GCOK;
|
||||
|
||||
/*
|
||||
* This unit is solely for the purpose of receiving event notifications
|
||||
*/
|
||||
uni = AsyncUnitFromQueue(assi);
|
||||
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int GenControllerConfigure(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[])
|
||||
{
|
||||
pSICSOBJ controller = NULL;
|
||||
pGenController self = NULL;
|
||||
char buffer[2048];
|
||||
|
||||
if (argc < 3) {
|
||||
snprintf(buffer, 2048, "ERROR: insufficient arguments to %s", argv[0]);
|
||||
SCWrite(pCon, buffer, eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
controller =
|
||||
(pSICSOBJ) FindCommandData(pSics, argv[2], "GenericController");
|
||||
if (controller == NULL) {
|
||||
snprintf(buffer, 2048, "ERROR: controller %s not found", argv[2]);
|
||||
SCWrite(pCon, buffer, eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
strtolower(argv[1]);
|
||||
if (strcmp(argv[1], "makepar") == 0) {
|
||||
return MakeGenPar(controller, pCon, argv, argc);
|
||||
} else if (strcmp(argv[1], "asynconnect") == 0) {
|
||||
return ConnectAsync(controller, pCon, argv, argc);
|
||||
} else {
|
||||
SCWrite(pCon, "ERROR: argument to GenControllerConfigure not found",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void killGeneric(void *data)
|
||||
{
|
||||
pGenController self = (pGenController) data;
|
||||
|
||||
if (self == NULL) {
|
||||
return;
|
||||
}
|
||||
if (self->comContext != NULL && self->killComContext != NULL) {
|
||||
self->killComContext(self->comContext);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int EnqueFunc(pSICSOBJ self, SConnection * pCon, pHdb commandNode,
|
||||
pHdb par[], int nPar)
|
||||
{
|
||||
pGenController priv = NULL;
|
||||
pHdb node = NULL;
|
||||
char buffer[512];
|
||||
|
||||
priv = (pGenController) self->pPrivate;
|
||||
assert(priv != NULL);
|
||||
assert(nPar >= 1);
|
||||
|
||||
node = GetHipadabaNode(self->objectNode, par[0]->value.v.text);
|
||||
if (node == NULL) {
|
||||
snprintf(buffer, 511, "ERROR: node %s to enqueue not found",
|
||||
par[0]->value.v.text);
|
||||
SCWrite(pCon, buffer, eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (priv->enqueueNode != NULL) {
|
||||
priv->enqueueNode(self, pCon, node);
|
||||
} else {
|
||||
SCWrite(pCon, "ERROR: GenController NOT configured", eError);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int EnqueHeadFunc(pSICSOBJ self, SConnection * pCon,
|
||||
Hdb commandNode, pHdb par[], int nPar)
|
||||
{
|
||||
pGenController priv = NULL;
|
||||
pHdb node = NULL;
|
||||
char buffer[512];
|
||||
|
||||
priv = (pGenController) self->pPrivate;
|
||||
assert(priv != NULL);
|
||||
assert(nPar >= 1);
|
||||
|
||||
node = GetHipadabaNode(self->objectNode, par[0]->value.v.text);
|
||||
if (node == NULL) {
|
||||
snprintf(buffer, 511, "ERROR: node %s to enqueue not found",
|
||||
par[0]->value.v.text);
|
||||
SCWrite(pCon, buffer, eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (priv->enqueueNodeHead != NULL) {
|
||||
priv->enqueueNodeHead(self, pCon, node);
|
||||
} else {
|
||||
SCWrite(pCon, "ERROR: GenController NOT configured", eError);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int GenControllerFactory(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[])
|
||||
{
|
||||
pSICSOBJ pNew = NULL;
|
||||
pGenController priv = NULL;
|
||||
hdbValue funcValue, textValue;
|
||||
pHdb node = NULL;
|
||||
char line[132];
|
||||
int status;
|
||||
|
||||
if (argc < 2) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: insufficient number of arguments to GenControllerFactrory",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
priv = malloc(sizeof(GenController));
|
||||
if (priv == NULL) {
|
||||
SCWrite(pCon, "ERROR: out of memory in GenControllerFactory", eError);
|
||||
return 0;
|
||||
}
|
||||
memset(priv, 0, sizeof(GenController));
|
||||
|
||||
pNew = MakeSICSOBJ(argv[1], "GenericController");
|
||||
if (pNew == NULL) {
|
||||
SCWrite(pCon, "ERROR: out of memory in GenControllerFactory", eError);
|
||||
return 0;
|
||||
}
|
||||
pNew->pPrivate = priv;
|
||||
pNew->KillPrivate = killGeneric;
|
||||
|
||||
textValue = MakeHdbText("Undefined");
|
||||
funcValue = MakeHdbFunc((voidFunc *) EnqueFunc);
|
||||
node = MakeSICSHdbPar("enqueue", usUser, funcValue);
|
||||
AddSICSHdbPar(node, "node", usUser, textValue);
|
||||
AppendHipadabaCallback(node, MakeSICSFuncCallback(pNew));
|
||||
AddHipadabaChild(pNew->objectNode, node, NULL);
|
||||
|
||||
funcValue = MakeHdbFunc((voidFunc *) EnqueHeadFunc);
|
||||
node = MakeSICSHdbPar("enqueuehead", usUser, funcValue);
|
||||
AddSICSHdbPar(node, "node", usUser, textValue);
|
||||
AppendHipadabaCallback(node, MakeSICSFuncCallback(pNew));
|
||||
AddHipadabaChild(pNew->objectNode, node, NULL);
|
||||
|
||||
status = AddCommand(pSics, argv[1], InvokeSICSOBJ, KillSICSOBJ, pNew);
|
||||
if (status != 1) {
|
||||
KillSICSOBJ(pNew);
|
||||
SCPrintf(pCon, eError, "ERROR: failed create duplicate command %s",
|
||||
argv[1]);
|
||||
return 0;
|
||||
}
|
||||
SCSendOK(pCon);
|
||||
|
||||
return 1;
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/**
|
||||
* This is a generic controller for devices in SICS. In its default configuration it
|
||||
* will be configurable via Tcl scripts and used AsynqQueue for communication. But
|
||||
* it is suitably generic to support other mechanisms as well.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, November 2007
|
||||
*/
|
||||
#ifndef GENERICCONTROLLER_H_
|
||||
#define GENERICCONTROLLER_H_
|
||||
#include <asyncqueue.h>
|
||||
#include <sicshipadaba.h>
|
||||
|
||||
#define GCTIMEOUT 5001
|
||||
#define GCDISCONNECT 5002
|
||||
#define GCOK 5000
|
||||
#define GCRECONNECT 5003
|
||||
#define GCRETRY 5004
|
||||
|
||||
typedef struct {
|
||||
int (*enqueueNode) (pSICSOBJ self, SConnection * pCon, pHdb node);
|
||||
int (*enqueueNodeHead) (pSICSOBJ self, SConnection * pCon, pHdb node);
|
||||
int (*replyCallback) (pSICSOBJ self, SConnection * pCon, pHdb node,
|
||||
char *replyCommand, char *reply, int replylen);
|
||||
void *comContext;
|
||||
void (*killComContext) (void *data);
|
||||
int comError;
|
||||
} GenController, *pGenController;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int GenControllerFactory(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[]);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int GenControllerConfigure(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[]);
|
||||
|
||||
#endif /*GENERICCONTROLLER_H_ */
|
524
hdbqueue.c
524
hdbqueue.c
@ -1,524 +0,0 @@
|
||||
/**
|
||||
* This is the new Hipadaba based queuing system in support of the MountainGum
|
||||
* user interface.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, July 2007
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <sics.h>
|
||||
#include "sicsobj.h"
|
||||
#include "hdbqueue.h"
|
||||
#include "sicshipadaba.h"
|
||||
#include "dynstring.h"
|
||||
#include "exeman.h"
|
||||
#include "macro.h"
|
||||
/*--------------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
int iStop;
|
||||
int isRunning;
|
||||
SConnection *pCon;
|
||||
} HdbQueue, *pHdbQueue;
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static pHdbCallback CopyCallbackChain(pHdbCallback source)
|
||||
{
|
||||
pHdbCallback current = NULL;
|
||||
pHdbCallback result = NULL;
|
||||
pHdbCallback head = NULL;
|
||||
pHdbCallback tail = NULL;
|
||||
|
||||
current = source;
|
||||
while (current != NULL) {
|
||||
result = MakeHipadabaCallback(current->userCallback,
|
||||
current->userData,
|
||||
NULL, current->id, current->internalID);
|
||||
if (head == NULL) {
|
||||
head = result;
|
||||
tail = result;
|
||||
} else {
|
||||
tail->next = result;
|
||||
result->previous = tail;
|
||||
tail = result;
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static pHdb MakeNewEntry(char *name, pHdbCallback update)
|
||||
{
|
||||
pHdb entry = NULL, child = NULL;
|
||||
hdbValue v;
|
||||
|
||||
v = MakeHdbText("Undefined");
|
||||
entry = MakeHipadabaNode(name, HIPNONE, 1);
|
||||
entry->updateCallbacks = CopyCallbackChain(update);
|
||||
child = MakeSICSHdbPar("description", usUser, v);
|
||||
child->updateCallbacks = CopyCallbackChain(update);
|
||||
AddHipadabaChild(entry, child, NULL);
|
||||
child = MakeSICSHdbPar("commands", usUser, v);
|
||||
child->updateCallbacks = CopyCallbackChain(update);
|
||||
AddHipadabaChild(entry, child, NULL);
|
||||
child = MakeSICSHdbPar("log", usUser, v);
|
||||
child->updateCallbacks = CopyCallbackChain(update);
|
||||
AddHipadabaChild(entry, child, NULL);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int EnqueFunc(pSICSOBJ self, SConnection * pCon, Hdb commandNode,
|
||||
pHdb par[], int nPar)
|
||||
{
|
||||
pHdb entry = NULL;
|
||||
pHdb work = NULL;
|
||||
char name[80];
|
||||
hdbValue v;
|
||||
|
||||
if (nPar < 1) {
|
||||
SCWrite(pCon, "ERROR: internal: not enough parameters to EnqueFunc",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* new entry
|
||||
*/
|
||||
memset(&v, 0, sizeof(hdbValue));
|
||||
work = GetHipadabaNode(self->objectNode, "control/maxEntry");
|
||||
assert(work != NULL);
|
||||
snprintf(name, 80, "%3.3d", work->value.v.intValue);
|
||||
entry = MakeNewEntry(name, work->updateCallbacks);
|
||||
if (entry == NULL) {
|
||||
SCWrite(pCon, "ERROR: out of memory in EnqueFunc", eError);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Update maxEntry
|
||||
*/
|
||||
cloneHdbValue(&work->value, &v);
|
||||
v.v.intValue++;
|
||||
UpdateHipadabaPar(work, v, pCon);
|
||||
|
||||
work = GetHipadabaNode(self->objectNode, "queue");
|
||||
assert(work != NULL);
|
||||
AddHipadabaChild(work, entry, pCon);
|
||||
|
||||
/*
|
||||
* save description
|
||||
*/
|
||||
work = GetHipadabaNode(entry, "description");
|
||||
assert(work != NULL);
|
||||
UpdateHipadabaPar(work, par[0]->value, pCon);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int AddCmdData(pSICSOBJ self, SConnection * pCon, Hdb comNode,
|
||||
pHdb par[], int nPar)
|
||||
{
|
||||
pHdb work = NULL;
|
||||
pHdb commandNode = NULL;
|
||||
char name[80];
|
||||
pDynString txt = NULL;
|
||||
|
||||
if (nPar < 1) {
|
||||
SCWrite(pCon, "ERROR: internal: not enough parameters to AddCmdData",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
work = GetHipadabaNode(self->objectNode, "control/maxEntry");
|
||||
assert(work != NULL);
|
||||
snprintf(name, 80, "queue/%3.3d/commands", work->value.v.intValue - 1);
|
||||
commandNode = GetHipadabaNode(self->objectNode, name);
|
||||
if (commandNode == NULL) {
|
||||
SCWrite(pCon, "ERROR: Internal error in AddCommand", eError);
|
||||
return 0;
|
||||
}
|
||||
txt = CreateDynString(80, 80);
|
||||
if (strstr(commandNode->value.v.text, "Undefined") == NULL) {
|
||||
DynStringCopy(txt, commandNode->value.v.text);
|
||||
}
|
||||
DynStringConcat(txt, par[0]->value.v.text);
|
||||
DynStringConcat(txt, "\n");
|
||||
free(commandNode->value.v.text);
|
||||
commandNode->value.v.text = strdup(GetCharArray(txt));
|
||||
NotifyHipadabaPar(commandNode, pCon);
|
||||
DeleteDynString(txt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static void sequentialNames(pHdb obj, SConnection * pCon)
|
||||
{
|
||||
pHdb work = NULL;
|
||||
pHdb current = NULL;
|
||||
int count = 0;
|
||||
char name[80];
|
||||
|
||||
work = GetHipadabaNode(obj, "queue");
|
||||
assert(work != NULL);
|
||||
current = work->child;
|
||||
while (current != NULL) {
|
||||
snprintf(name, 80, "%3.3d", count);
|
||||
if (current->name != NULL) {
|
||||
free(current->name);
|
||||
}
|
||||
current->name = strdup(name);
|
||||
count++;
|
||||
current = current->next;
|
||||
}
|
||||
InvokeCallbackChain(work->treeChangeCallbacks, work, pCon, work->value);
|
||||
|
||||
work = GetHipadabaNode(obj, "control/maxEntry");
|
||||
assert(work != NULL);
|
||||
work->value.v.intValue = count;
|
||||
NotifyHipadabaPar(work, pCon);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int Dequeue(pSICSOBJ self, SConnection * pCon, pHdb commandNode,
|
||||
pHdb par[], int nPar)
|
||||
{
|
||||
pHdb work = NULL;
|
||||
char name[80];
|
||||
pHdbQueue priv = (pHdbQueue) self->pPrivate;
|
||||
|
||||
if (priv->isRunning == 1) {
|
||||
SCWrite(pCon, "ERROR: cannot dequeue while running", eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (nPar < 1) {
|
||||
SCWrite(pCon, "ERROR: internal: not enough parameters to Dequeue",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(name, 80, "queue/%3.3d", par[0]->value.v.intValue);
|
||||
work = GetHipadabaNode(self->objectNode, name);
|
||||
if (work != NULL) {
|
||||
DeleteHipadabaNode(work, pCon);
|
||||
sequentialNames(self->objectNode, pCon);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int Clean(pSICSOBJ self, SConnection * pCon, Hdb commandNode,
|
||||
pHdb par[], int nPar)
|
||||
{
|
||||
int i;
|
||||
pHdb current = NULL, queue = NULL;
|
||||
pHdb currentEntry = NULL, tmp = NULL;
|
||||
pHdbQueue priv = (pHdbQueue) self->pPrivate;
|
||||
|
||||
if (priv->isRunning == 1) {
|
||||
SCWrite(pCon, "ERROR: cannot clean while running", eError);
|
||||
return 0;
|
||||
}
|
||||
currentEntry = GetHipadabaNode(self->objectNode, "control/currentEntry");
|
||||
queue = GetHipadabaNode(self->objectNode, "queue");
|
||||
current = queue->child;
|
||||
for (i = 0; i < currentEntry->value.v.intValue; i++) {
|
||||
if (current != NULL) {
|
||||
tmp = current->next;
|
||||
DeleteNodeData(current);
|
||||
current = tmp;
|
||||
}
|
||||
}
|
||||
queue->child = tmp;
|
||||
currentEntry->value.v.intValue = 0;
|
||||
sequentialNames(self->objectNode, pCon);
|
||||
NotifyHipadabaPar(currentEntry, pCon);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int CleanAll(pSICSOBJ self, SConnection * pCon, pHdb commandNode,
|
||||
pHdb par[], int nPar)
|
||||
{
|
||||
int i;
|
||||
pHdb current = NULL, queue = NULL;
|
||||
pHdb currentEntry = NULL, tmp;
|
||||
pHdbQueue priv = (pHdbQueue) self->pPrivate;
|
||||
|
||||
if (priv->isRunning == 1) {
|
||||
SCWrite(pCon, "ERROR: cannot clear queue while executing", eError);
|
||||
return 0;
|
||||
}
|
||||
currentEntry = GetHipadabaNode(self->objectNode, "control/currentEntry");
|
||||
queue = GetHipadabaNode(self->objectNode, "queue");
|
||||
current = queue->child;
|
||||
while (current != NULL) {
|
||||
tmp = current->next;
|
||||
DeleteNodeData(current);
|
||||
current = tmp;
|
||||
}
|
||||
queue->child = NULL;
|
||||
currentEntry->value.v.intValue = 0;
|
||||
sequentialNames(self->objectNode, pCon);
|
||||
NotifyHipadabaPar(currentEntry, pCon);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int QueueTask(void *pData)
|
||||
{
|
||||
pSICSOBJ self = (pSICSOBJ) pData;
|
||||
int status, pos;
|
||||
pHdb work = NULL;
|
||||
pHdb exeNode = NULL;
|
||||
pHdb max = NULL;
|
||||
char name[80];
|
||||
pHdbQueue priv = (pHdbQueue) self->pPrivate;
|
||||
|
||||
if (priv->iStop == 1) {
|
||||
priv->isRunning = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
work = GetHipadabaNode(self->objectNode, "control/currentEntry");
|
||||
max = GetHipadabaNode(self->objectNode, "control/maxEntry");
|
||||
assert(work != NULL && max != NULL);
|
||||
pos = work->value.v.intValue;
|
||||
snprintf(name, 80, "queue/%3.3d", pos);
|
||||
|
||||
exeNode = GetHipadabaNode(self->objectNode, name);
|
||||
if (exeNode != NULL) {
|
||||
MacroPush(priv->pCon);
|
||||
exeHdbNode(exeNode, priv->pCon);
|
||||
MacroPop();
|
||||
}
|
||||
if (priv->iStop == 1 || SCGetInterrupt(priv->pCon) != eContinue) {
|
||||
priv->isRunning = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos++;
|
||||
work->value.v.intValue = pos;
|
||||
NotifyHipadabaPar(work, priv->pCon);
|
||||
if (pos >= max->value.v.intValue) {
|
||||
priv->isRunning = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int Start(pSICSOBJ self, SConnection * pCon, pHdb commandNode,
|
||||
pHdb par[], int nPar)
|
||||
{
|
||||
pHdbQueue priv = (pHdbQueue) self->pPrivate;
|
||||
|
||||
priv->iStop = 0;
|
||||
priv->pCon = pCon;
|
||||
|
||||
if (priv->isRunning == 1) {
|
||||
SCWrite(pCon, "ERROR: Hdbqueue is already running", eError);
|
||||
return 0;
|
||||
}
|
||||
priv->isRunning = 1;
|
||||
|
||||
TaskRegister(pServ->pTasker, QueueTask, NULL, NULL, self, 10);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int Restart(pSICSOBJ self, SConnection * pCon, pHdb commandNode,
|
||||
pHdb par[], int nPar)
|
||||
{
|
||||
pHdbQueue priv = (pHdbQueue) self->pPrivate;
|
||||
pHdb maxCurrent = NULL;
|
||||
|
||||
maxCurrent = GetHipadabaNode(self->objectNode, "control/currentEntry");
|
||||
if (maxCurrent != NULL) {
|
||||
maxCurrent->value.v.intValue = 0;
|
||||
NotifyHipadabaPar(maxCurrent, pCon);
|
||||
}
|
||||
|
||||
return Start(self, pCon, commandNode, par, nPar);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int Stop(pSICSOBJ self, SConnection * pCon, pHdb commandNode,
|
||||
pHdb par[], int nPar)
|
||||
{
|
||||
pHdbQueue priv = (pHdbQueue) self->pPrivate;
|
||||
|
||||
priv->iStop = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int Move(pSICSOBJ self, SConnection * pCon, pHdb commandNode,
|
||||
pHdb par[], int nPar)
|
||||
{
|
||||
pHdb moveNode = NULL;
|
||||
pHdb insertNode = NULL;
|
||||
pHdb prevNode = NULL, queueNode = NULL;
|
||||
pHdb tmp;
|
||||
char name[80];
|
||||
pHdbQueue priv = (pHdbQueue) self->pPrivate;
|
||||
|
||||
if (priv->isRunning == 1) {
|
||||
SCWrite(pCon, "ERROR: cannot move while running", eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nPar < 2) {
|
||||
SCWrite(pCon, "ERROR: internal: not enough parameters to Move",
|
||||
eError);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (par[1]->value.v.intValue == par[0]->value.v.intValue + 1) {
|
||||
/*
|
||||
* already in right sequence, nothing to do
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
snprintf(name, 80, "queue/%3.3d", par[1]->value.v.intValue);
|
||||
moveNode = GetHipadabaNode(self->objectNode, name);
|
||||
|
||||
snprintf(name, 80, "queue/%3.3d", par[0]->value.v.intValue);
|
||||
insertNode = GetHipadabaNode(self->objectNode, name);
|
||||
if (moveNode == NULL || insertNode == NULL) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: move not possible, participating nodes not found",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
queueNode = GetHipadabaNode(self->objectNode, "queue");
|
||||
|
||||
if (moveNode == queueNode->child) {
|
||||
queueNode->child = queueNode->child->next;
|
||||
moveNode->next = insertNode->next;
|
||||
insertNode->next = moveNode;
|
||||
} else {
|
||||
prevNode = queueNode->child;
|
||||
while (prevNode != NULL && prevNode->next != moveNode) {
|
||||
prevNode = prevNode->next;
|
||||
}
|
||||
if (insertNode == queueNode->child) {
|
||||
/*
|
||||
* insert at top
|
||||
*/
|
||||
tmp = queueNode->child;
|
||||
queueNode->child = moveNode;
|
||||
prevNode->next = moveNode->next;
|
||||
moveNode->next = tmp;
|
||||
} else {
|
||||
tmp = insertNode->next;
|
||||
insertNode->next = moveNode;
|
||||
prevNode->next = moveNode->next;
|
||||
moveNode->next = tmp;
|
||||
}
|
||||
}
|
||||
sequentialNames(self->objectNode, pCon);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void Configure(pSICSOBJ self)
|
||||
{
|
||||
pHdb n = NULL, par = NULL;
|
||||
hdbValue intValue, textValue, funcValue;
|
||||
pHdb obj = self->objectNode;
|
||||
|
||||
intValue = MakeHdbInt(0);
|
||||
textValue = MakeHdbText("Undefined");
|
||||
|
||||
n = MakeHipadabaNode("control", HIPNONE, 1);
|
||||
AddHipadabaChild(obj, n, NULL);
|
||||
AddSICSHdbPar(n, "maxEntry", usInternal, intValue);
|
||||
AddSICSHdbPar(n, "currentEntry", usInternal, intValue);
|
||||
|
||||
|
||||
n = MakeHipadabaNode("queue", HIPNONE, 1);
|
||||
AddHipadabaChild(obj, n, NULL);
|
||||
|
||||
funcValue = MakeSICSFunc(EnqueFunc);
|
||||
n = MakeSICSHdbPar("enqueue", usUser, funcValue);
|
||||
AddSICSHdbPar(n, "description", usUser, textValue);
|
||||
AddHipadabaChild(obj, n, NULL);
|
||||
AppendHipadabaCallback(n, HCBSET, MakeSICSFuncCallback(self));
|
||||
|
||||
funcValue = MakeSICSFunc(AddCmdData);
|
||||
n = MakeSICSHdbPar("addcommand", usUser, funcValue);
|
||||
AddSICSHdbPar(n, "command", usUser, textValue);
|
||||
AddHipadabaChild(obj, n, NULL);
|
||||
AppendHipadabaCallback(n, HCBSET, MakeSICSFuncCallback(self));
|
||||
|
||||
|
||||
funcValue = MakeSICSFunc(Dequeue);
|
||||
n = MakeSICSHdbPar("dequeue", usUser, funcValue);
|
||||
AddHipadabaChild(obj, n, NULL);
|
||||
AddSICSHdbPar(n, "index", usUser, intValue);
|
||||
AppendHipadabaCallback(n, HCBSET, MakeSICSFuncCallback(self));
|
||||
|
||||
|
||||
funcValue = MakeSICSFunc(Clean);
|
||||
n = MakeSICSHdbPar("clean", usUser, funcValue);
|
||||
AddHipadabaChild(obj, n, NULL);
|
||||
AppendHipadabaCallback(n, HCBSET, MakeSICSFuncCallback(self));
|
||||
|
||||
funcValue = MakeSICSFunc(CleanAll);
|
||||
n = MakeSICSHdbPar("cleanall", usUser, funcValue);
|
||||
AddHipadabaChild(obj, n, NULL);
|
||||
AppendHipadabaCallback(n, HCBSET, MakeSICSFuncCallback(self));
|
||||
|
||||
funcValue = MakeSICSFunc(Start);
|
||||
n = MakeSICSHdbPar("start", usUser, funcValue);
|
||||
AddHipadabaChild(obj, n, NULL);
|
||||
AppendHipadabaCallback(n, HCBSET, MakeSICSFuncCallback(self));
|
||||
|
||||
funcValue = MakeSICSFunc(Restart);
|
||||
n = MakeSICSHdbPar("restart", usUser, funcValue);
|
||||
AddHipadabaChild(obj, n, NULL);
|
||||
AppendHipadabaCallback(n, HCBSET, MakeSICSFuncCallback(self));
|
||||
|
||||
funcValue = MakeSICSFunc(Stop);
|
||||
n = MakeSICSHdbPar("stop", usUser, funcValue);
|
||||
AddHipadabaChild(obj, n, NULL);
|
||||
AppendHipadabaCallback(n, HCBSET, MakeSICSFuncCallback(self));
|
||||
|
||||
funcValue = MakeSICSFunc(Move);
|
||||
n = MakeSICSHdbPar("move", usUser, funcValue);
|
||||
AddHipadabaChild(obj, n, NULL);
|
||||
AddSICSHdbPar(n, "moveindex", usUser, intValue);
|
||||
AddSICSHdbPar(n, "insertindex", usUser, intValue);
|
||||
AppendHipadabaCallback(n, HCBSET, MakeSICSFuncCallback(self));
|
||||
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int MakeHDBQueue(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
pSICSOBJ self = NULL;
|
||||
pHdbQueue priv = NULL;
|
||||
|
||||
priv = (pHdbQueue) malloc(sizeof(HdbQueue));
|
||||
self = SetupSICSOBJ(pCon, pSics, pData, argc, argv);
|
||||
if (self == NULL || priv == NULL) {
|
||||
return 0;
|
||||
}
|
||||
Configure(self);
|
||||
memset(priv, 0, sizeof(HdbQueue));
|
||||
self->pPrivate = priv;
|
||||
self->KillPrivate = free;
|
||||
return 1;
|
||||
}
|
15
hdbqueue.h
15
hdbqueue.h
@ -1,15 +0,0 @@
|
||||
/**
|
||||
* This is the new Hipadab based queuing system in support of the MountainGum
|
||||
* user interface.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, July 2007
|
||||
*/
|
||||
#ifndef HDBQUEUE_H_
|
||||
#define HDBQUEUE_H_
|
||||
|
||||
int MakeHDBQueue(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
#endif /*HDBQUEUE_H_ */
|
402
hklscan.c
402
hklscan.c
@ -1,402 +0,0 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
H K L S C A N
|
||||
|
||||
A class for doing scans in reciprocal space for a four circle
|
||||
diffractometer. All the hard work is done in the scan and hkl objects.
|
||||
|
||||
copyright: see copyright.h
|
||||
|
||||
Mark Koennecke, June 1999
|
||||
|
||||
This is obsolete: h,k,l are now drivable. Logged variables have been added
|
||||
to the scan module. The command is now implemented through scripts.
|
||||
This module is left in the source tree in order to allow for a quick
|
||||
reinstallation in case of problems but should be retired from the
|
||||
source tree in the shutdown 2007
|
||||
|
||||
Mark Koennecke, January 2006
|
||||
--------------------------------------------------------------------------*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <tcl.h>
|
||||
#include "fortify.h"
|
||||
#include "sics.h"
|
||||
#include "scan.h"
|
||||
#include "hkl.h"
|
||||
#include "scan.i"
|
||||
#include "matrix/matrix.h"
|
||||
#include "hkl.i"
|
||||
#include "hklscan.i"
|
||||
#include "hklscan.h"
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static void KillHklscan(void *pData)
|
||||
{
|
||||
pHklscan self = NULL;
|
||||
|
||||
self = (pHklscan) pData;
|
||||
if (!self) {
|
||||
return;
|
||||
}
|
||||
if (self->pDes) {
|
||||
DeleteDescriptor(self->pDes);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
int HklscanFactory(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[4])
|
||||
{
|
||||
pHklscan pNew = NULL;
|
||||
char pBueffel[512];
|
||||
int iRet;
|
||||
|
||||
/* check number of arguments */
|
||||
if (argc < 3) {
|
||||
SCWrite(pCon, "ERROR: expected two arguments to MakeHklscan", eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* allocate space */
|
||||
pNew = (pHklscan) malloc(sizeof(sHklscan));
|
||||
if (!pNew) {
|
||||
SCWrite(pCon, "ERROR: out of memory in MakeHklscan", eError);
|
||||
return 0;
|
||||
}
|
||||
memset(pNew, 0, sizeof(sHklscan));
|
||||
pNew->pDes = CreateDescriptor("Hklscan");
|
||||
|
||||
/* find scan object */
|
||||
pNew->pScan = (pScanData) FindCommandData(pSics, argv[1], "ScanObject");
|
||||
if (!pNew->pScan) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: %s not found or no scan object", argv[1]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
KillHklscan(pNew);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* find HKL object */
|
||||
pNew->pCalc = (pHKL) FindCommandData(pSics, argv[2],
|
||||
"4-Circle-Calculus");
|
||||
if (!pNew->pCalc) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: %s not found or no HKL object", argv[2]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
KillHklscan(pNew);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* alright. Install command */
|
||||
iRet = AddCommand(pSics, "__hklscan", HklscanAction, KillHklscan, pNew);
|
||||
if (!iRet) {
|
||||
SCWrite(pCon, "ERROR: duplicate command hklscan NOT created", eError);
|
||||
KillHklscan(pNew);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
static int HklscanDrive(pScanData pScan, int iPoint)
|
||||
{
|
||||
pHklscan self = NULL;
|
||||
int i, iRet;
|
||||
|
||||
assert(pScan);
|
||||
self = (pHklscan) pScan->pSpecial;
|
||||
assert(self);
|
||||
|
||||
/* calculate new Positions */
|
||||
for (i = 0; i < 3; i++) {
|
||||
self->fPos[i] = self->fStart[i] + iPoint * self->fStep[i];
|
||||
}
|
||||
iRet = DriveHKL(self->pCalc, self->fPos, 0., 0, pScan->pCon);
|
||||
if (!iRet) {
|
||||
SCWrite(pScan->pCon, "ERROR: aborting hklscan", eError);
|
||||
}
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
static int WriteHklscanPoint(pScanData self, int iPoint)
|
||||
{
|
||||
pHklscan pHaSca = NULL;
|
||||
int i, i2;
|
||||
char pLine[512], pItem[30], pInfo[512];
|
||||
pVarEntry pVar = NULL;
|
||||
pCountEntry pData = NULL;
|
||||
void *pPtr = NULL;
|
||||
|
||||
assert(self);
|
||||
pHaSca = (pHklscan) self->pSpecial;
|
||||
assert(pHaSca);
|
||||
|
||||
|
||||
assert(self->pCon);
|
||||
assert(self->pSics);
|
||||
|
||||
if (!self->fd) {
|
||||
self->fd = fopen(self->pFile, "r+");
|
||||
if (!self->fd) {
|
||||
SCWrite(self->pCon, "ERROR: failed to reopen scan file during scan",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* jump to end of header */
|
||||
fseek(self->fd, self->lPos, SEEK_SET);
|
||||
if (self->iChannel != 0) {
|
||||
fprintf(self->fd, "WARNING: Scanning monitor %d\n", self->iChannel);
|
||||
}
|
||||
|
||||
/* make the data header */
|
||||
snprintf(pLine,sizeof(pLine)-1, "%-5s", "NP");
|
||||
snprintf(pInfo,sizeof(pInfo)-1, "Scanning Variables: H, K, L STEP: %8.3f %8.3f %8.3f",
|
||||
pHaSca->fStep[0], pHaSca->fStep[1], pHaSca->fStep[2]);
|
||||
strcat(pLine, "H K L ");
|
||||
for (i = 0; i < self->iScanVar; i++) {
|
||||
DynarGet(self->pScanVar, i, &pPtr);
|
||||
pVar = (pVarEntry) pPtr;
|
||||
if (pVar) {
|
||||
snprintf(pItem,sizeof(pItem)-1, "%-6.6s ", pVar->Name);
|
||||
strcat(pLine, pItem);
|
||||
}
|
||||
}
|
||||
strcat(pLine, "Counts ");
|
||||
strcat(pLine, " Monitor1 ");
|
||||
snprintf(pItem,sizeof(pItem)-1, "\n%d Points,", self->iNP);
|
||||
strcat(pInfo, pItem);
|
||||
if (self->iMode == eTimer) {
|
||||
strcat(pInfo, " Mode: Timer,");
|
||||
} else {
|
||||
strcat(pInfo, " Mode: Monitor,");
|
||||
}
|
||||
snprintf(pItem,sizeof(pItem)-1, " Preset %f", self->fPreset);
|
||||
strcat(pInfo, pItem);
|
||||
fprintf(self->fd, "%s\n", pInfo);
|
||||
fprintf(self->fd, "%s\n", pLine);
|
||||
|
||||
/* print an addon to the status line going to the screen */
|
||||
snprintf(pLine,sizeof(pLine)-1, "NP H K L ");
|
||||
SCWrite(self->pCon, pLine, eWarning);
|
||||
snprintf(pLine,sizeof(pLine)-1, "%-5d%-8.4f%-8.4f%-8.4f ", iPoint, pHaSca->fPos[0],
|
||||
pHaSca->fPos[1], pHaSca->fPos[2]);
|
||||
SCWrite(self->pCon, pLine, eWarning);
|
||||
|
||||
/* now the scan points */
|
||||
for (i = 0; i < self->iCounts; i++) {
|
||||
snprintf(pLine,sizeof(pLine)-1, "%-5d", i);
|
||||
/* print HKL */
|
||||
for (i2 = 0; i2 < 3; i2++) {
|
||||
snprintf(pItem,sizeof(pItem)-1, " %-8.4f",
|
||||
pHaSca->fStart[i2] + i * pHaSca->fStep[i2]);
|
||||
strcat(pLine, pItem);
|
||||
}
|
||||
/* print chi, ph, om */
|
||||
for (i2 = 0; i2 < self->iScanVar; i2++) {
|
||||
DynarGet(self->pScanVar, i2, &pPtr);
|
||||
pVar = (pVarEntry) pPtr;
|
||||
if (pVar) {
|
||||
snprintf(pItem,sizeof(pItem)-1, " %-7.2f", GetScanVarPos(pVar, i));
|
||||
strcat(pLine, pItem);
|
||||
}
|
||||
}
|
||||
/* print Counts & Monitor */
|
||||
DynarGet(self->pCounts, i, &pPtr);
|
||||
pData = (pCountEntry) pPtr;
|
||||
if (pData) {
|
||||
snprintf(pItem,sizeof(pItem)-1, " %-13ld", pData->lCount);
|
||||
strcat(pLine, pItem);
|
||||
snprintf(pItem,sizeof(pItem)-1, " %-12ld", pData->Monitors[0]);
|
||||
strcat(pLine, pItem);
|
||||
}
|
||||
fprintf(self->fd, "%s\n", pLine);
|
||||
}
|
||||
|
||||
/* done */
|
||||
fprintf(self->fd, "END-OF-DATA\n");
|
||||
fclose(self->fd);
|
||||
self->fd = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
int Hklscan(pHklscan self, SConnection * pCon,
|
||||
int iNP, int iMode, float fPreset)
|
||||
{
|
||||
int iRet;
|
||||
float fVal;
|
||||
|
||||
assert(self);
|
||||
|
||||
/* configure the scan thing for our bizarre purpose */
|
||||
ClearScanVar(self->pScan);
|
||||
MotorGetPar(self->pCalc->pTheta, "softlowerlim", &fVal);
|
||||
fVal += .5;
|
||||
AddScanVar(self->pScan, pServ->pSics, pCon, self->pCalc->pTheta->name,
|
||||
fVal, 0.);
|
||||
MotorGetPar(self->pCalc->pOmega, "softlowerlim", &fVal);
|
||||
fVal += .5;
|
||||
AddScanVar(self->pScan, pServ->pSics, pCon, self->pCalc->pOmega->name,
|
||||
fVal, 0.);
|
||||
MotorGetPar(self->pCalc->pChi, "softlowerlim", &fVal);
|
||||
fVal += .5;
|
||||
AddScanVar(self->pScan, pServ->pSics, pCon, self->pCalc->pChi->name,
|
||||
fVal, 0.);
|
||||
MotorGetPar(self->pCalc->pPhi, "softlowerlim", &fVal);
|
||||
fVal += .5;
|
||||
AddScanVar(self->pScan, pServ->pSics, pCon, self->pCalc->pPhi->name,
|
||||
fVal, 0.);
|
||||
self->pScan->WriteScanPoints = WriteHklscanPoint;
|
||||
self->pScan->ScanDrive = HklscanDrive;
|
||||
self->pScan->pSpecial = self;
|
||||
self->pScan->PrepareScan = NonCheckPrepare;
|
||||
|
||||
/* scan */
|
||||
iRet = DoScan(self->pScan, iNP, iMode, fPreset, pServ->pSics, pCon);
|
||||
|
||||
/* unset all */
|
||||
ClearScanVar(self->pScan);
|
||||
ResetScanFunctions(self->pScan);
|
||||
self->pScan->pSpecial = NULL;
|
||||
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
int HklscanAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
char pBueffel[512];
|
||||
int iRet, iMode, iNP, iPoint;
|
||||
pHklscan self = NULL;
|
||||
double dVal;
|
||||
float fPreset;
|
||||
void *pPtr;
|
||||
|
||||
assert(pCon);
|
||||
assert(pSics);
|
||||
assert(pData);
|
||||
|
||||
self = (pHklscan) pData;
|
||||
|
||||
/* check for the command word */
|
||||
if (argc < 2) {
|
||||
SCWrite(pCon, "ERROR: Insufficient number of arguments to hklscan",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do work according to command word */
|
||||
strtolower(argv[1]);
|
||||
if (strcmp(argv[1], "start") == 0) {
|
||||
if (!SCMatchRights(pCon, usUser)) {
|
||||
return 0;
|
||||
}
|
||||
if (argc < 5) {
|
||||
SCWrite(pCon,
|
||||
"Insufficient number of arguments to hklscan", eError);
|
||||
return 0;
|
||||
}
|
||||
iRet = Tcl_GetDouble(pSics->pTcl, argv[2], &dVal);
|
||||
if (iRet != TCL_OK) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: failed to convert %s to number", argv[2]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
self->fStart[0] = (float) dVal;
|
||||
iRet = Tcl_GetDouble(pSics->pTcl, argv[3], &dVal);
|
||||
if (iRet != TCL_OK) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: failed to convert %s to number", argv[3]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
self->fStart[1] = (float) dVal;
|
||||
iRet = Tcl_GetDouble(pSics->pTcl, argv[4], &dVal);
|
||||
if (iRet != TCL_OK) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: failed to convert %s to number", argv[4]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
self->fStart[2] = (float) dVal;
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else if (strcmp(argv[1], "step") == 0) {
|
||||
if (!SCMatchRights(pCon, usUser)) {
|
||||
return 0;
|
||||
}
|
||||
if (argc < 5) {
|
||||
SCWrite(pCon,
|
||||
"Insufficient number of arguments to hklscan", eError);
|
||||
return 0;
|
||||
}
|
||||
iRet = Tcl_GetDouble(pSics->pTcl, argv[2], &dVal);
|
||||
if (iRet != TCL_OK) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: failed to convert %s to number", argv[2]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
self->fStep[0] = (float) dVal;
|
||||
iRet = Tcl_GetDouble(pSics->pTcl, argv[3], &dVal);
|
||||
if (iRet != TCL_OK) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: failed to convert %s to number", argv[3]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
self->fStep[1] = (float) dVal;
|
||||
iRet = Tcl_GetDouble(pSics->pTcl, argv[4], &dVal);
|
||||
if (iRet != TCL_OK) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: failed to convert %s to number", argv[4]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
self->fStep[2] = (float) dVal;
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else if (strcmp(argv[1], "run") == 0) {
|
||||
if (!SCMatchRights(pCon, usUser)) {
|
||||
return 0;
|
||||
}
|
||||
if (argc < 5) {
|
||||
SCWrite(pCon,
|
||||
"Insufficient number of arguments to hklscan run", eError);
|
||||
return 0;
|
||||
}
|
||||
iRet = Tcl_GetInt(pSics->pTcl, argv[2], &iNP);
|
||||
if (iRet != TCL_OK) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: failed to convert %s to number", argv[2]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
/* interpret Mode */
|
||||
if (strcmp(argv[3], "timer") == 0) {
|
||||
iMode = eTimer;
|
||||
} else if (strcmp(argv[3], "monitor") == 0) {
|
||||
iMode = ePreset;
|
||||
} else {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: %s not recognized as valid counter mode",
|
||||
argv[3]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
/* preset */
|
||||
iRet = Tcl_GetDouble(pSics->pTcl, argv[4], &dVal);
|
||||
if (iRet != TCL_OK) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: expected number, got %s", argv[3]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
fPreset = (float) dVal;
|
||||
iRet = Hklscan(self, pCon, iNP, iMode, fPreset);
|
||||
if (iRet) {
|
||||
SCSendOK(pCon);
|
||||
}
|
||||
return iRet;
|
||||
}
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1,
|
||||
"ERROR: %s not recognized as command word to hklscan", argv[1]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
25
hklscan.h
25
hklscan.h
@ -1,25 +0,0 @@
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
H K L S C A N
|
||||
|
||||
A class for doing scans in reciprocal space. This makes only sense at an
|
||||
four circle diffractometer. Most of the work is done in the HKL and scan
|
||||
objects. This class just adapts and used both objects to do the right thing.
|
||||
|
||||
Mark Koennecke, June 1999
|
||||
---------------------------------------------------------------------------*/
|
||||
#ifndef HKLSCAN
|
||||
#define HKLSCAN
|
||||
|
||||
typedef struct __HKLSCAN *pHklscan;
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int HklScan(pHklscan self, SConnection * pCon, int iNP, int iMode,
|
||||
float fPreset);
|
||||
/*---------------- interpreter functions -----------------------------------*/
|
||||
int HklscanFactory(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
int HklscanAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
|
||||
#endif
|
17
hklscan.i
17
hklscan.i
@ -1,17 +0,0 @@
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
Internal data structure for the hklscan object. DO NOT MODIFY.
|
||||
Modifications only in hklscan.i
|
||||
|
||||
Mark Koennecke, June 1999
|
||||
--------------------------------------------------------------------------*/
|
||||
|
||||
typedef struct __HKLSCAN {
|
||||
pObjectDescriptor pDes;
|
||||
pScanData pScan;
|
||||
pHKL pCalc;
|
||||
float fStart[3];
|
||||
float fStep[3];
|
||||
float fPos[3];
|
||||
} sHklscan;
|
||||
|
111
hklscan.tex
111
hklscan.tex
@ -1,111 +0,0 @@
|
||||
\subsection{hklscan}
|
||||
hklscan is an object which implements scanning in reciprocal space. It belongs
|
||||
to the four circle diffraction line of commands. It requires the hkl object
|
||||
for doing four circle calculations and a scan object for doing the scanning.
|
||||
The scan object is configured by overloading its WriteScanPoints and
|
||||
ScanDrive functions to do the right thing for this. Thus most of the work
|
||||
is done in scan and hkl.
|
||||
|
||||
hklscan has its own data structure looking like this:
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap1}
|
||||
$\langle$hklscandat {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ typedef struct __HKLSCAN {@\\
|
||||
\mbox{}\verb@ pObjectDescriptor pDes;@\\
|
||||
\mbox{}\verb@ pScanData pScan;@\\
|
||||
\mbox{}\verb@ pHKL pCalc; @\\
|
||||
\mbox{}\verb@ float fStart[3];@\\
|
||||
\mbox{}\verb@ float fStep[3];@\\
|
||||
\mbox{}\verb@ float fPos[3];@\\
|
||||
\mbox{}\verb@ } sHklscan;@\\
|
||||
\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 object descriptor.
|
||||
\item[pScan] The scan object used for scanning.
|
||||
\item[pCalc] The hkl object used for crystallographic computations.
|
||||
\item[fStart] The start values in H, K, L for scanning.
|
||||
\item[fStep] The step width in H, K, L.
|
||||
\item[fPos] The last position in H, K, L.
|
||||
\end{description}
|
||||
|
||||
The hklscan object defines the following external interface:
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap2}
|
||||
$\langle$hklscanfunc {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ typedef struct __HKLSCAN *pHklscan;@\\
|
||||
\mbox{}\verb@/*--------------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@ int HklScan(pHklscan self, SConnection *pCon, int iNP, int iMode,@\\
|
||||
\mbox{}\verb@ float fPreset);@\\
|
||||
\mbox{}\verb@/*---------------- interpreter functions -----------------------------------*/@\\
|
||||
\mbox{}\verb@ int HklscanFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
|
||||
\mbox{}\verb@ int argc, char *argv[]);@\\
|
||||
\mbox{}\verb@ int HklscanAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
|
||||
\mbox{}\verb@ int argc, char *argv[]);@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item Macro referenced in scrap ?.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap3}
|
||||
\verb@"hklscan.i"@ {\footnotesize ? }$\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
|
||||
\mbox{}\verb@ Internal data structure for the hklscan object. DO NOT MODIFY. @\\
|
||||
\mbox{}\verb@ Modifications only in hklscan.i@\\
|
||||
\mbox{}\verb@ @\\
|
||||
\mbox{}\verb@ Mark Koennecke, June 1999@\\
|
||||
\mbox{}\verb@--------------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@@$\langle$hklscandat {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-2ex}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap4}
|
||||
\verb@"hklscan.h"@ {\footnotesize ? }$\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@/*--------------------------------------------------------------------------@\\
|
||||
\mbox{}\verb@ H K L S C A N@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ A class for doing scans in reciprocal space. This makes only sense at an@\\
|
||||
\mbox{}\verb@ four circle diffractometer. Most of the work is done in the HKL and scan@\\
|
||||
\mbox{}\verb@ objects. This class just adapts and used both objects to do the right thing.@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ Mark Koennecke, June 1999@\\
|
||||
\mbox{}\verb@---------------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@#ifndef HKLSCAN@\\
|
||||
\mbox{}\verb@#define HKLSCAN@\\
|
||||
\mbox{}\verb@@$\langle$hklscanfunc {\footnotesize ?}$\rangle$\verb@@\\
|
||||
\mbox{}\verb@#endif@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-2ex}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
70
hklscan.w
70
hklscan.w
@ -1,70 +0,0 @@
|
||||
\subsection{hklscan}
|
||||
hklscan is an object which implements scanning in reciprocal space. It belongs
|
||||
to the four circle diffraction line of commands. It requires the hkl object
|
||||
for doing four circle calculations and a scan object for doing the scanning.
|
||||
The scan object is configured by overloading its WriteScanPoints and
|
||||
ScanDrive functions to do the right thing for this. Thus most of the work
|
||||
is done in scan and hkl.
|
||||
|
||||
hklscan has its own data structure looking like this:
|
||||
|
||||
@d hklscandat @{
|
||||
typedef struct __HKLSCAN {
|
||||
pObjectDescriptor pDes;
|
||||
pScanData pScan;
|
||||
pHKL pCalc;
|
||||
float fStart[3];
|
||||
float fStep[3];
|
||||
float fPos[3];
|
||||
} sHklscan;
|
||||
@}
|
||||
\begin{description}
|
||||
\item[pDes] The standard object descriptor.
|
||||
\item[pScan] The scan object used for scanning.
|
||||
\item[pCalc] The hkl object used for crystallographic computations.
|
||||
\item[fStart] The start values in H, K, L for scanning.
|
||||
\item[fStep] The step width in H, K, L.
|
||||
\item[fPos] The last position in H, K, L.
|
||||
\end{description}
|
||||
|
||||
The hklscan object defines the following external interface:
|
||||
|
||||
@d hklscanfunc @{
|
||||
typedef struct __HKLSCAN *pHklscan;
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int HklScan(pHklscan self, SConnection *pCon, int iNP, int iMode,
|
||||
float fPreset);
|
||||
/*---------------- interpreter functions -----------------------------------*/
|
||||
int HklscanFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
int HklscanAction(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
@}
|
||||
|
||||
@o hklscan.i @{
|
||||
/*-------------------------------------------------------------------------
|
||||
Internal data structure for the hklscan object. DO NOT MODIFY.
|
||||
Modifications only in hklscan.i
|
||||
|
||||
Mark Koennecke, June 1999
|
||||
--------------------------------------------------------------------------*/
|
||||
@<hklscandat@>
|
||||
@}
|
||||
|
||||
@o hklscan.h @{
|
||||
/*--------------------------------------------------------------------------
|
||||
H K L S C A N
|
||||
|
||||
A class for doing scans in reciprocal space. This makes only sense at an
|
||||
four circle diffractometer. Most of the work is done in the HKL and scan
|
||||
objects. This class just adapts and used both objects to do the right thing.
|
||||
|
||||
Mark Koennecke, June 1999
|
||||
---------------------------------------------------------------------------*/
|
||||
#ifndef HKLSCAN
|
||||
#define HKLSCAN
|
||||
@<hklscanfunc@>
|
||||
#endif
|
||||
@}
|
||||
|
4
make_gen
4
make_gen
@ -12,7 +12,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
|
||||
macro.o ofac.o obpar.o obdes.o drive.o status.o intserv.o \
|
||||
devexec.o mumo.o mumoconf.o selector.o selvar.o fupa.o lld.o \
|
||||
lld_blob.o strrepl.o lin2ang.o fomerge.o napi5.o napi4.o\
|
||||
script.o o2t.o alias.o napi.o nxdata.o stringdict.o sdynar.o \
|
||||
script.o o2t.o alias.o napi.o stringdict.o sdynar.o \
|
||||
histmem.o histdriv.o histsim.o interface.o callback.o nxio.o \
|
||||
event.o emon.o evcontroller.o evdriver.o simev.o perfmon.o \
|
||||
danu.o nxdict.o varlog.o stptok.o nread.o trigd.o cell.o\
|
||||
@ -36,7 +36,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
|
||||
moregress.o multicounter.o regresscter.o histregress.o \
|
||||
sicshdbadapter.o polldriv.o sicspoll.o statemon.o hmslave.o \
|
||||
nwatch.o asyncqueue.o asyncprotocol.o sicsobj.o frame.o\
|
||||
nxcopy.o nxinterhelper.o nxinter_wrap.o genericcontroller.o nxstack.o \
|
||||
nxcopy.o nxinterhelper.o nxinter_wrap.o nxstack.o \
|
||||
sctdriveadapter.o sctdriveobj.o reflist.o singlex.o fourmess.o \
|
||||
sgclib.o sgfind.o sgio.o sgsi.o sghkl.o singlediff.o singlebi.o \
|
||||
singlenb.o simindex.o simidx.o uselect.o singletas.o motorsec.o \
|
||||
|
814
nxdata.c
814
nxdata.c
@ -1,814 +0,0 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
N X D A T A
|
||||
|
||||
This implements the data file writing for the Powder diffractometers
|
||||
HRPT and DMC.
|
||||
|
||||
Mark Koennecke, March-April 1997
|
||||
|
||||
Updated and expanded: Mark Koennecke, November 1999
|
||||
|
||||
Copyright:
|
||||
|
||||
Labor fuer Neutronenstreuung
|
||||
Paul Scherrer Institut
|
||||
CH-5423 Villigen-PSI
|
||||
|
||||
|
||||
The authors hereby grant permission to use, copy, modify, distribute,
|
||||
and license this software and its documentation for any purpose, provided
|
||||
that existing copyright notices are retained in all copies and that this
|
||||
notice is included verbatim in any distributions. No written agreement,
|
||||
license, or royalty fee is required for any of the authorized uses.
|
||||
Modifications to this software may be copyrighted by their authors
|
||||
and need not follow the licensing terms described here, provided that
|
||||
the new terms are clearly indicated on the first page of each file where
|
||||
they apply.
|
||||
|
||||
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
||||
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
||||
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
||||
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
||||
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
||||
MODIFICATIONS.
|
||||
----------------------------------------------------------------------------*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include "fortify.h"
|
||||
#include "sics.h"
|
||||
#include "sicsvar.h"
|
||||
#include "nxdict.h"
|
||||
#include "modriv.h"
|
||||
#include "motor.h"
|
||||
#include "nxdata.h"
|
||||
#include "nxutil.h"
|
||||
#include "selector.h"
|
||||
#include "selvar.h"
|
||||
#include "countdriv.h"
|
||||
#include "counter.h"
|
||||
#include "danu.h"
|
||||
#include "HistMem.h"
|
||||
#include "udpquieck.h"
|
||||
#include "evcontroller.h"
|
||||
#include "nxscript.h"
|
||||
|
||||
|
||||
#define DMCDETNAM "DMC-BF3-Detector"
|
||||
#define DMCDETOB "detector"
|
||||
#define HRPTDETNAM "Cerca-Detector"
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static void SNError(void *pData, char *text)
|
||||
{
|
||||
SConnection *pCon;
|
||||
|
||||
assert(pData);
|
||||
pCon = (SConnection *) pData;
|
||||
SCWrite(pCon, text, eError);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
char *SNXMakeFileName(SicsInterp * pSics, SConnection * pCon)
|
||||
{
|
||||
char *pPtr = NULL;
|
||||
pPtr = makeFilename(pSics, pCon);
|
||||
if (pPtr == NULL) {
|
||||
pPtr = strdup("emergency.hdf");
|
||||
}
|
||||
return pPtr;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
char *SNXMakeFileNameOld(SicsInterp * pSics, SConnection * pCon)
|
||||
{
|
||||
pSicsVariable pPath = NULL, pPref = NULL, pEnd = NULL;
|
||||
char *pRes = NULL;
|
||||
int iLen, iNum, iYear;
|
||||
char pNumText[10];
|
||||
CommandList *pCom = NULL;
|
||||
|
||||
/* Try, get all the Variables */
|
||||
pPath = FindVariable(pSics, "sicsdatapath");
|
||||
pPref = FindVariable(pSics, "sicsdataprefix");
|
||||
pCom = FindCommand(pSics, "sicsdatanumber");
|
||||
pEnd = FindVariable(pSics, "sicsdatapostfix");
|
||||
|
||||
if ((!pPath) || (!pPref) || (!pCom) || (!pEnd)) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: cannot read variables for automatic data file name creation",
|
||||
eError);
|
||||
SCWrite(pCon,
|
||||
"ERROR: This is a VERY, VERY, VERY serious installation problem",
|
||||
eError);
|
||||
SCWrite(pCon, "ERROR: your data will be dumped into emergency.hdf",
|
||||
eError);
|
||||
return strdup("emergency.hdf");
|
||||
}
|
||||
|
||||
/* find length */
|
||||
iLen = strlen(pPath->text);
|
||||
iLen += strlen(pPref->text);
|
||||
iLen += 8; /* for number + year */
|
||||
iLen += strlen(pEnd->text);
|
||||
iLen += 10; /* safety margin */
|
||||
|
||||
/* allocate memory */
|
||||
pRes = (char *) malloc(iLen * sizeof(char));
|
||||
if (!pRes) {
|
||||
SCWrite(pCon, "ERROR: no memory in SNXMakeFileName", eError);
|
||||
return NULL;
|
||||
}
|
||||
memset(pRes, 0, iLen);
|
||||
|
||||
/* build the filename */
|
||||
strcpy(pRes, pPath->text);
|
||||
strcat(pRes, pPref->text);
|
||||
iNum = IncrementDataNumber(pCom->pData, &iYear);
|
||||
if (iNum < 0) {
|
||||
SCWrite(pCon, "ERROR: cannot increment data number!", eError);
|
||||
SCWrite(pCon, "ERROR: your data will be dumped to emergency.hdf",
|
||||
eError);
|
||||
free(pRes);
|
||||
return strdup("emergency.hdf");
|
||||
}
|
||||
sprintf(pNumText, "%5.5d", iNum);
|
||||
strcat(pRes, pNumText);
|
||||
sprintf(pNumText, "%4.4d", iYear);
|
||||
strcat(pRes, pNumText);
|
||||
strcat(pRes, pEnd->text);
|
||||
|
||||
|
||||
/* install an error handler */
|
||||
NXMSetError((void *) pCon, SNError);
|
||||
|
||||
return pRes;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
NXhandle SNXStartFile(SConnection * pCon, SicsInterp * pSics)
|
||||
{
|
||||
NXhandle pFile = NULL;
|
||||
char *filename = NULL;
|
||||
pSicsVariable pVar = NULL;
|
||||
int iStat;
|
||||
char pBueffel[512], pTime[132];
|
||||
|
||||
/* 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);
|
||||
free(filename);
|
||||
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);
|
||||
}
|
||||
|
||||
/* filename no longer needed */
|
||||
free(filename);
|
||||
|
||||
/* write creation time */
|
||||
SNXFormatTime(pTime, 132);
|
||||
iStat = NXputattr(pFile, "file_time", pTime, strlen(pTime) + 1, NX_CHAR);
|
||||
if (iStat == NX_ERROR) {
|
||||
SCWrite(pCon, "ERROR: writing date attribute to Nexus file", eError);
|
||||
}
|
||||
sprintf(pBueffel, "File created at StarDate: %s", pTime);
|
||||
SCWrite(pCon, pBueffel, eWarning);
|
||||
|
||||
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, "address");
|
||||
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 SNXStartEntry(NXhandle Nfil, int iNew, SicsInterp * pSics)
|
||||
{
|
||||
int iStat;
|
||||
char pName[80];
|
||||
pSicsVariable pVar = NULL;
|
||||
int iDim[2];
|
||||
|
||||
/* format an entry name */
|
||||
if (iNew < 10) {
|
||||
sprintf(pName, "entry%1.1d", iNew);
|
||||
} else if ((iNew > 9) && (iNew < 100)) {
|
||||
sprintf(pName, "entry%2.2d", iNew);
|
||||
} else if ((iNew > 99) && (iNew < 1000)) {
|
||||
sprintf(pName, "entry%3.3d", iNew);
|
||||
} else if ((iNew > 9999) && (iNew < 10000)) {
|
||||
sprintf(pName, "entry%4.4d", iNew);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create entry and step into it */
|
||||
iStat = NXmakegroup(Nfil, pName, "NXentry");
|
||||
if (iStat == NX_ERROR) {
|
||||
return 0;
|
||||
}
|
||||
iStat = NXopengroup(Nfil, pName, "NXentry");
|
||||
if (iStat == NX_ERROR) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* write entry level attributes here */
|
||||
pVar = FindVariable(pSics, "title");
|
||||
if (pVar) {
|
||||
iDim[0] = strlen(pVar->text) + 1;
|
||||
NXmakedata(Nfil, "title", NX_CHAR, 1, iDim);
|
||||
NXopendata(Nfil, "title");
|
||||
NXputdata(Nfil, pVar->text);
|
||||
NXclosedata(Nfil);
|
||||
}
|
||||
/* write time */
|
||||
SNXFormatTime(pName, 79);
|
||||
iDim[0] = strlen(pName) + 1;
|
||||
NXmakedata(Nfil, "start_time", NX_CHAR, 1, iDim);
|
||||
NXopendata(Nfil, "start_time");
|
||||
NXputdata(Nfil, pName);
|
||||
NXclosedata(Nfil);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
int SNenter(NXhandle Nfil, char *name, char *class)
|
||||
{
|
||||
int iStat;
|
||||
|
||||
iStat = NXmakegroup(Nfil, name, class);
|
||||
if (iStat == NX_ERROR) {
|
||||
NXclose(&Nfil);
|
||||
return 0;
|
||||
}
|
||||
iStat = NXopengroup(Nfil, name, class);
|
||||
if (iStat == NX_ERROR) {
|
||||
NXclose(&Nfil);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
int SNputdata1(NXhandle Nfil, char *name, int datatype, int iLong,
|
||||
void *pData)
|
||||
{
|
||||
int iStat;
|
||||
int iDim[2];
|
||||
|
||||
iDim[0] = iLong;
|
||||
iStat = NXmakedata(Nfil, name, datatype, 1, (int *) iDim);
|
||||
if (iStat == NX_ERROR) {
|
||||
NXclose(&Nfil);
|
||||
return 0;
|
||||
}
|
||||
iStat = NXopendata(Nfil, name);
|
||||
if (iStat == NX_ERROR) {
|
||||
NXclose(&Nfil);
|
||||
return 0;
|
||||
}
|
||||
iStat = NXputdata(Nfil, pData);
|
||||
if (iStat == NX_ERROR) {
|
||||
NXclose(&Nfil);
|
||||
return 0;
|
||||
}
|
||||
iStat = NXclosedata(Nfil);
|
||||
if (iStat == NX_ERROR) {
|
||||
NXclose(&Nfil);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
int SNputdata1att(NXhandle Nfil, char *name, int datatype, int iLong,
|
||||
void *pData, char *attname, char *val)
|
||||
{
|
||||
int iStat;
|
||||
int iDim[2];
|
||||
|
||||
iDim[0] = iLong;
|
||||
iStat = NXmakedata(Nfil, name, datatype, 1, (int *) iDim);
|
||||
if (iStat == NX_ERROR) {
|
||||
NXclose(&Nfil);
|
||||
return 0;
|
||||
}
|
||||
iStat = NXopendata(Nfil, name);
|
||||
if (iStat == NX_ERROR) {
|
||||
NXclose(&Nfil);
|
||||
return 0;
|
||||
}
|
||||
iStat = NXputdata(Nfil, pData);
|
||||
if (iStat == NX_ERROR) {
|
||||
NXclose(&Nfil);
|
||||
return 0;
|
||||
}
|
||||
iStat = NXputattr(Nfil, attname, val, strlen(val) + 1, NX_CHAR);
|
||||
if (iStat == NX_ERROR) {
|
||||
NXclose(&Nfil);
|
||||
return 0;
|
||||
}
|
||||
iStat = NXclosedata(Nfil);
|
||||
if (iStat == NX_ERROR) {
|
||||
NXclose(&Nfil);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static int SNPutMotor(NXhandle hfil, SicsInterp * pSics,
|
||||
SConnection * pCon, char *sicsname,
|
||||
char *dataname, char *units)
|
||||
{
|
||||
float fVal;
|
||||
char pBueffel[512];
|
||||
int iRet;
|
||||
pMotor pMot;
|
||||
|
||||
pMot = FindMotor(pSics, sicsname);
|
||||
if (!pMot) {
|
||||
sprintf(pBueffel, "ERROR: motor %s not found ", sicsname);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
iRet = MotorGetSoftPosition(pMot, pCon, &fVal);
|
||||
if (iRet != 1) {
|
||||
sprintf(pBueffel, "ERROR: cannot read motor %s", sicsname);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
return SNputdata1att(hfil, dataname, NX_FLOAT32, 1, &fVal, "Units",
|
||||
units);
|
||||
}
|
||||
|
||||
#ifdef NONINTF
|
||||
extern float nintf(float f);
|
||||
#endif
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int SNMakeDMC(SConnection * pCon, SicsInterp * pSics)
|
||||
{
|
||||
NXhandle Nfil;
|
||||
NXlink lWave, lDetData, lStart, lTemp, lMoni, lStep, lNumber,
|
||||
lTheta, lSetData;
|
||||
int iDim[2];
|
||||
float fEnd, fStart, fStep;
|
||||
int iStat;
|
||||
pSicsVariable pVar;
|
||||
pSicsSelector pSel = NULL;
|
||||
pICountable pCountInt;
|
||||
pIDrivable pDrive = NULL;
|
||||
pSelVar pPell;
|
||||
char *pP;
|
||||
float fVal;
|
||||
float *fTheta;
|
||||
float fTh, f2Th, fB1, fB2;
|
||||
pMotor pMot = NULL;
|
||||
CommandList *pCom = NULL;
|
||||
int iVal, i;
|
||||
char pBuffer[132];
|
||||
pHistMem pHist = NULL;
|
||||
HistInt *lData = NULL;
|
||||
CounterMode eCount;
|
||||
int *iTVal = NULL;
|
||||
pDummy pDum;
|
||||
int bHRPT = 0;
|
||||
float fMean, fStdDev;
|
||||
pVarLog pLog = NULL;
|
||||
|
||||
/* open the file & entry */
|
||||
Nfil = SNXStartFile(pCon, pSics);
|
||||
if (!Nfil) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
iStat = SNXStartEntry(Nfil, 1, pSics);
|
||||
if (!iStat) {
|
||||
NXclose(&Nfil);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create the instrument Vgroup */
|
||||
pVar = FindVariable(pSics, "instrument");
|
||||
if (strcmp(pVar->text, "HRPT") == 0) {
|
||||
bHRPT = 1;
|
||||
}
|
||||
assert(pVar);
|
||||
iStat = SNenter(Nfil, pVar->text, "NXpsdpowder");
|
||||
if (!iStat) {
|
||||
return 0;
|
||||
}
|
||||
/* write the Kollimator for HRPT */
|
||||
if (bHRPT) {
|
||||
iStat = SNenter(Nfil, "kollimator", "NXkollimator");
|
||||
if (!iStat) {
|
||||
return 0;
|
||||
}
|
||||
pMot = FindMotor(pSics, "CEX1");
|
||||
if (pMot) {
|
||||
iStat = MotorGetSoftPosition(pMot, pCon, &fStart);
|
||||
iStat = SNputdata1att(Nfil, "kollimator1", NX_FLOAT32, 1,
|
||||
&fStart, "Units", "degrees");
|
||||
}
|
||||
pMot = FindMotor(pSics, "CEX2");
|
||||
if (pMot) {
|
||||
iStat = MotorGetSoftPosition(pMot, pCon, &fStart);
|
||||
iStat = SNputdata1att(Nfil, "kollimator2", NX_FLOAT32, 1,
|
||||
&fStart, "Units", "degrees");
|
||||
}
|
||||
NXclosegroup(Nfil); /* leave kollimator */
|
||||
}
|
||||
|
||||
/* write the Monochromator data */
|
||||
iStat = SNenter(Nfil, "Monochromator", "NXcrystal");
|
||||
if (!iStat) {
|
||||
return 0;
|
||||
}
|
||||
if (bHRPT) {
|
||||
pVar = FindVariable(pSics, "lambda");
|
||||
if (pVar) {
|
||||
VarGetFloat(pVar, &fVal);
|
||||
SNputdata1att(Nfil, "lambda", NX_FLOAT32, 1, &fVal,
|
||||
"Units", "Angstroem");
|
||||
NXopendata(Nfil, "lambda");
|
||||
NXgetdataID(Nfil, &lWave);
|
||||
NXclosedata(Nfil);
|
||||
}
|
||||
pVar = FindVariable(pSics, "monotype");
|
||||
if (pVar) {
|
||||
iStat = SNputdata1(Nfil, "type", NX_CHAR, strlen(pVar->text),
|
||||
pVar->text);
|
||||
}
|
||||
/* write tons of motors for the monochromator */
|
||||
SNPutMotor(Nfil, pSics, pCon, "momu", "omega_upper", "degree");
|
||||
SNPutMotor(Nfil, pSics, pCon, "mtvu",
|
||||
"vertical_translation_upper", "mm");
|
||||
SNPutMotor(Nfil, pSics, pCon, "mtpu",
|
||||
"paralell_translation_upper", "mm");
|
||||
SNPutMotor(Nfil, pSics, pCon, "mgvu", "vertical_tilt_upper", "degree");
|
||||
SNPutMotor(Nfil, pSics, pCon, "mgpu", "parallel_tilt_upper", "degree");
|
||||
SNPutMotor(Nfil, pSics, pCon, "mcvu", "curvature_upper", "");
|
||||
SNPutMotor(Nfil, pSics, pCon, "moml", "omega_lower", "degree");
|
||||
SNPutMotor(Nfil, pSics, pCon, "mtvl",
|
||||
"vertical_translation_lower", "mm");
|
||||
SNPutMotor(Nfil, pSics, pCon, "mtpl",
|
||||
"parallel_translation_lower", "degree");
|
||||
SNPutMotor(Nfil, pSics, pCon, "mgvl", "vertical_tilt_lower", "degree");
|
||||
SNPutMotor(Nfil, pSics, pCon, "mgpl", "parallel_tilt_lower", "degree");
|
||||
SNPutMotor(Nfil, pSics, pCon, "mcvl", "curvature_lower", "degree");
|
||||
SNPutMotor(Nfil, pSics, pCon, "mexz", "lift", "mm");
|
||||
} else {
|
||||
pCom = FindCommand(pSics, "mono");
|
||||
assert(pCom);
|
||||
pSel = (pSicsSelector) pCom->pData;
|
||||
pP = MonoGetType(pSel);
|
||||
iStat = SNputdata1(Nfil, "type", NX_CHAR, strlen(pP), pP);
|
||||
if (!iStat) {
|
||||
return 0;
|
||||
}
|
||||
pCom = NULL;
|
||||
pCom = FindCommand(pSics, "lambda");
|
||||
assert(pCom);
|
||||
pPell = (pSelVar) pCom->pData;
|
||||
assert(iHasType(pPell, "SicsSelVar"));
|
||||
fVal = GetSelValue(pPell, pCon);
|
||||
iStat = SNputdata1(Nfil, "lambda", NX_FLOAT32, 1, &fVal);
|
||||
if (!iStat) {
|
||||
return 0;
|
||||
}
|
||||
NXopendata(Nfil, "lambda");
|
||||
NXputattr(Nfil, "Units", "Angstroem", 10, NX_CHAR);
|
||||
NXgetdataID(Nfil, &lWave);
|
||||
NXclosedata(Nfil);
|
||||
iStat = GetMonoPositions(pSel, pCon, &fTh, &f2Th, &fB1, &fB2);
|
||||
if (iStat)
|
||||
/* skip if not readable, error has been reported lower down */
|
||||
{
|
||||
SNputdata1att(Nfil, "theta", NX_FLOAT32, 1, &fTh,
|
||||
"Units", "degrees");
|
||||
SNputdata1att(Nfil, "two_theta", NX_FLOAT32, 1, &f2Th,
|
||||
"Units", "degrees");
|
||||
SNputdata1att(Nfil, "curvature", NX_FLOAT32, 1, &fB1, "Units", "mm");
|
||||
}
|
||||
/* more monochromatic motors */
|
||||
SNPutMotor(Nfil, pSics, pCon, "monox", "x_translation", "mm");
|
||||
SNPutMotor(Nfil, pSics, pCon, "monoy", "y_translation", "mm");
|
||||
SNPutMotor(Nfil, pSics, pCon, "monophi", "phi", "degree");
|
||||
SNPutMotor(Nfil, pSics, pCon, "monochi", "chi", "degree");
|
||||
}
|
||||
NXclosegroup(Nfil); /* leave monochromator */
|
||||
|
||||
/* start Detector vGroup */
|
||||
if (bHRPT) {
|
||||
iStat = SNenter(Nfil, HRPTDETNAM, "NXpsd");
|
||||
} else {
|
||||
iStat = SNenter(Nfil, DMCDETNAM, "NXpsd");
|
||||
}
|
||||
/* get the histogram memory object */
|
||||
pCom = FindCommand(pSics, "banana");
|
||||
assert(pCom);
|
||||
pHist = pCom->pData;
|
||||
assert(pHist);
|
||||
|
||||
/* counter mode */
|
||||
eCount = GetHistCountMode(pHist);
|
||||
if (eCount == eTimer) {
|
||||
strcpy(pBuffer, "Timer");
|
||||
} else {
|
||||
strcpy(pBuffer, "Monitor");
|
||||
}
|
||||
iStat =
|
||||
SNputdata1(Nfil, "CounterMode", NX_CHAR, strlen(pBuffer), pBuffer);
|
||||
if (!iStat) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* count preset */
|
||||
fVal = GetHistPreset(pHist);
|
||||
if (eCount == eTimer) {
|
||||
iStat = SNputdata1(Nfil, "Preset", NX_FLOAT32, 1, &fVal);
|
||||
} else {
|
||||
fVal = nintf(fVal);
|
||||
iStat = SNputdata1(Nfil, "Preset", NX_FLOAT32, 1, &fVal);
|
||||
}
|
||||
if (!iStat) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* monitor value */
|
||||
pDum = (pDummy) pHist;
|
||||
pCountInt = pDum->pDescriptor->GetInterface(pDum, COUNTID);
|
||||
{
|
||||
pCountInt->TransferData(pHist, pCon);
|
||||
}
|
||||
iVal = GetHistMonitor(pHist, 1, pCon);
|
||||
if (iVal < 0) {
|
||||
return 0;
|
||||
}
|
||||
iStat = SNputdata1(Nfil, "Monitor", NX_INT32, 1, &iVal);
|
||||
/*
|
||||
count time
|
||||
*/
|
||||
fVal = GetHistCountTime(pHist, pCon);
|
||||
SNputdata1att(Nfil, "time", NX_FLOAT32, 1, &fVal, "Units", "seconds");
|
||||
|
||||
/*
|
||||
more monitors
|
||||
*/
|
||||
iVal = GetHistMonitor(pHist, 0, pCon);
|
||||
SNputdata1(Nfil, "beam_monitor", NX_INT32, 1, &iVal);
|
||||
iVal = GetHistMonitor(pHist, 4, pCon);
|
||||
SNputdata1(Nfil, "proton_monitor", NX_INT32, 1, &iVal);
|
||||
NXopendata(Nfil, "Monitor");
|
||||
NXgetdataID(Nfil, &lMoni);
|
||||
NXclosedata(Nfil);
|
||||
|
||||
|
||||
/* stepwidth */
|
||||
pVar = FindVariable(pSics, "detstepwidth");
|
||||
if (!pVar) {
|
||||
return 0;
|
||||
}
|
||||
fVal = pVar->fVal;
|
||||
iStat = SNputdata1(Nfil, "Step", NX_FLOAT32, 1, &fVal);
|
||||
if (!iStat) {
|
||||
return 0;
|
||||
}
|
||||
NXopendata(Nfil, "Step");
|
||||
NXgetdataID(Nfil, &lStep);
|
||||
NXclosedata(Nfil);
|
||||
|
||||
/* histogram Length */
|
||||
GetHistDim(pHist, iDim, &iVal);
|
||||
iVal = iDim[0];
|
||||
if (iVal < 1) {
|
||||
return 0;
|
||||
}
|
||||
iStat = SNputdata1(Nfil, "no_of_steps", NX_INT32, 1, &iVal);
|
||||
if (iStat < 1) {
|
||||
return 0;
|
||||
}
|
||||
NXopendata(Nfil, "no_of_steps");
|
||||
NXgetdataID(Nfil, &lNumber);
|
||||
NXclosedata(Nfil);
|
||||
|
||||
/* actual data */
|
||||
lData = (HistInt *) malloc(iVal * sizeof(HistInt));
|
||||
if (!lData) {
|
||||
return 0;
|
||||
}
|
||||
iStat =
|
||||
GetHistogram(pHist, pCon, 0, 0, iVal, lData, iVal * sizeof(HistInt));
|
||||
if (!iStat) {
|
||||
return 0;
|
||||
}
|
||||
iStat = SNputdata1(Nfil, "Counts", NX_INT32, iVal, lData);
|
||||
if (!iStat) {
|
||||
return 0;
|
||||
}
|
||||
free(lData);
|
||||
NXopendata(Nfil, "Counts");
|
||||
NXgetdataID(Nfil, &lSetData);
|
||||
strcpy(pBuffer, "1");
|
||||
NXputattr(Nfil, "signal", pBuffer, strlen(pBuffer) + 1, NX_CHAR);
|
||||
NXclosedata(Nfil);
|
||||
|
||||
/* motor position */
|
||||
pMot = FindMotor(pSics, "a4");
|
||||
assert(pMot);
|
||||
iStat = MotorGetSoftPosition(pMot, pCon, &fStart);
|
||||
iStat = SNputdata1att(Nfil, "two_theta_start", NX_FLOAT32, 1,
|
||||
&fStart, "Units", "degrees");
|
||||
if (!iStat) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create 2Theta array and store it */
|
||||
fTheta = NULL;
|
||||
fTheta = (float *) malloc(iVal * sizeof(NX_FLOAT32));
|
||||
if (!fTheta) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < iVal; i++) {
|
||||
fTheta[i] = fStart + i * fVal;
|
||||
}
|
||||
iStat = SNputdata1att(Nfil, "two_theta", NX_FLOAT32, iVal,
|
||||
fTheta, "Units", "degrees");
|
||||
if (!iStat) {
|
||||
return 0;
|
||||
}
|
||||
/* get link, put axis attribute */
|
||||
NXopendata(Nfil, "two_theta");
|
||||
NXputattr(Nfil, "axis", "1", strlen("1") + 1, NX_CHAR);
|
||||
NXgetdataID(Nfil, &lTheta);
|
||||
NXclosedata(Nfil);
|
||||
free(fTheta);
|
||||
|
||||
|
||||
NXopendata(Nfil, "two_theta_start");
|
||||
NXgetdataID(Nfil, &lStart);
|
||||
NXclosedata(Nfil);
|
||||
NXclosegroup(Nfil); /* detector Vgroup */
|
||||
NXclosegroup(Nfil); /* instrument Vgroup */
|
||||
|
||||
/* do the sample Vgroup */
|
||||
iStat = SNenter(Nfil, "Sample", "NXpowder");
|
||||
if (!iStat) {
|
||||
return 0;
|
||||
}
|
||||
pVar = FindVariable(pSics, "sample");
|
||||
if (pVar) {
|
||||
iDim[0] = strlen(pVar->text) + 1;
|
||||
NXmakedata(Nfil, "sample_name", NX_CHAR, 1, iDim);
|
||||
NXopendata(Nfil, "sample_name");
|
||||
NXputdata(Nfil, pVar->text);
|
||||
NXclosedata(Nfil);
|
||||
}
|
||||
pVar = FindVariable(pSics, "sample_mur");
|
||||
if (pVar) {
|
||||
SNputdata1att(Nfil, "sample_mur", NX_FLOAT32, 1, &pVar->fVal,
|
||||
"Units", "???");
|
||||
}
|
||||
/* do a3 */
|
||||
SNPutMotor(Nfil, pSics, pCon, "a3", "sample_table_rotation", "degree");
|
||||
|
||||
/* 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 */
|
||||
pLog = EVCGetVarLog((pEVControl) pCom->pData);
|
||||
if (pLog) {
|
||||
VarlogGetMean(pLog, &fMean, &fStdDev);
|
||||
SNputdata1att(Nfil, "temperature_mean", NX_FLOAT32, 1, &fMean,
|
||||
"Units", "K");
|
||||
SNputdata1att(Nfil, "temperature_stddev", NX_FLOAT32, 1,
|
||||
&fStdDev, "Units", "K");
|
||||
}
|
||||
fVal = pDrive->GetValue(pCom->pData, pCon);
|
||||
} else { /* a simple variable */
|
||||
|
||||
VarGetFloat((pSicsVariable) pDum, &fVal);
|
||||
}
|
||||
SNputdata1att(Nfil, "sample_temperature", NX_FLOAT32, 1, &fVal,
|
||||
"Units", "K");
|
||||
}
|
||||
NXclosegroup(Nfil); /* sample Vgroup */
|
||||
|
||||
/* write the data Vgroup */
|
||||
SNenter(Nfil, "data1", "NXdata");
|
||||
NXmakelink(Nfil, &lWave);
|
||||
NXmakelink(Nfil, &lTheta);
|
||||
NXmakelink(Nfil, &lStart);
|
||||
NXmakelink(Nfil, &lSetData);
|
||||
NXmakelink(Nfil, &lMoni);
|
||||
NXmakelink(Nfil, &lStep);
|
||||
NXmakelink(Nfil, &lNumber);
|
||||
|
||||
/* send quieck message */
|
||||
i = 131;
|
||||
iVal = NX_CHAR;
|
||||
NXgetattr(Nfil, "file_name", pBuffer, &i, &iVal);
|
||||
SendQuieck(QUIECK, pBuffer);
|
||||
|
||||
/* done */
|
||||
NXclose(&Nfil);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int SNStoreDMC(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
return SNMakeDMC(pCon, pSics);
|
||||
}
|
29
nxdata.h
29
nxdata.h
@ -1,29 +0,0 @@
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
N X D A T A
|
||||
|
||||
Some routines for handling Nexus data file writing.
|
||||
|
||||
Mark Koennecke, April 1997
|
||||
|
||||
copyright: see implementation file.
|
||||
--------------------------------------------------------------------------*/
|
||||
#ifndef SICSNXDATA
|
||||
#define SICSNXDATA
|
||||
|
||||
char *SNXMakeFileName(SicsInterp * pSics, SConnection * pCon);
|
||||
|
||||
NXhandle SNXStartFile(SConnection * pCon, SicsInterp * pSics);
|
||||
|
||||
int SNXStartEntry(NXhandle Nfil, int iNew, SicsInterp * pSics);
|
||||
|
||||
void SNXFormatTime(char *pBuffer, int iBufLen);
|
||||
|
||||
int SNFinishFile(NXhandle Nfil);
|
||||
|
||||
int SNMakeDMC(SConnection * pCon, SicsInterp * pSics);
|
||||
|
||||
int SNStoreDMC(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
#endif
|
192
nxdata.tex
192
nxdata.tex
@ -1,192 +0,0 @@
|
||||
\subsection{NXdata}
|
||||
NXdata is a module for writing Powder Diffraction Data files. The
|
||||
routines here are somewhat obsolete as they refer to NeXus writing
|
||||
using the standard Napi routines which is quite involved. Usually,
|
||||
NeXus files are written from SICS through the NXDICT aware utility
|
||||
routines in NXUTIL.
|
||||
|
||||
If not stated
|
||||
otherwise, all routines return 1 on successful completion and 0 when an
|
||||
error is detected. Please note, that many of these routines expect to find
|
||||
certain data items in the Sics Interpreter. This implies, that any naming
|
||||
changes in the initialisation file might force changes in here as well.
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap1}
|
||||
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ char *SNXMakeFileName(SicsInterp *pSics, SConnection *pCon);@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item Macro defined by scraps ?, ?, ?, ?, ?, ?, ?.
|
||||
\item Macro referenced in scrap ?.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
SNXMakeFileName creates a new filename from the SICS variables SicsDataPath,
|
||||
SicsDataPresript, SicsDataNumber and SicsDataEnding. SicsDataNumber will be
|
||||
incremented as well. The function returns a newly allocate buffer with the
|
||||
assembled filename or NULL on error. Note, that the caller is responsible
|
||||
for freeing the memory associated with the filename afterwards.
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap2}
|
||||
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ NXhandle SNXStartFile(SConnection *pCon, SicsInterp *pSics); @\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item Macro defined by scraps ?, ?, ?, ?, ?, ?, ?.
|
||||
\item Macro referenced in scrap ?.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
First calls SNXMakeFileName in order to get a new Filename.
|
||||
Then a new Nexus file is
|
||||
created and all the standard headings are filled in: Filename, User,
|
||||
instrument, date etc. This routine also installs an error handler which
|
||||
prints errors to pCon.
|
||||
If successful, the SicsDataNumber is incremented and
|
||||
an NXhandle into the new file is returned. If there is a problem, NULL
|
||||
will be returned. The file returned will be positioned at root level.
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap3}
|
||||
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ int SNXStartEntry(NXhandle Nfil, int iNew, SicsInterp *pSics);@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item Macro defined by scraps ?, ?, ?, ?, ?, ?, ?.
|
||||
\item Macro referenced in scrap ?.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap4}
|
||||
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ void SNXFormatTime(char *pBuffer, int iBufLen);@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item Macro defined by scraps ?, ?, ?, ?, ?, ?, ?.
|
||||
\item Macro referenced in scrap ?.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
SNXFormatTime formats the current system time in a form compatible to the
|
||||
NeXus standard. Input parameters is a Buffer to hold the string and a
|
||||
length of the buffer. Maximum iBufLen characters will be copied to that
|
||||
buffer.
|
||||
|
||||
SNXStartEntry creates a new entry corresponding to iNew in the Nexus file
|
||||
Nfil. SNXStartEntry will position Nfil in this new entry. Any data items
|
||||
labeled as Comment or intent will be written to the file as well.
|
||||
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap5}
|
||||
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ int SNFinishFile(NXhandle Nfil);@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item Macro defined by scraps ?, ?, ?, ?, ?, ?, ?.
|
||||
\item Macro referenced in scrap ?.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
SNFinishFile will end a Nexus file properly.
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap6}
|
||||
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ int SNMakeDMC(SConnection *pCon, SicsInterp *pSics);@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item Macro defined by scraps ?, ?, ?, ?, ?, ?, ?.
|
||||
\item Macro referenced in scrap ?.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
SNMakeDMC produces a Nexus DMC data file from the currently valid
|
||||
information. It orchestrates all of the above.
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap7}
|
||||
$\langle$Protos {\footnotesize ?}$\rangle\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@int SNStoreDMC(SConnection *pCon, SicsInterp *pSics, void *pData, int argc,@\\
|
||||
\mbox{}\verb@ char *argv[]);@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}}
|
||||
\item Macro defined by scraps ?, ?, ?, ?, ?, ?, ?.
|
||||
\item Macro referenced in scrap ?.
|
||||
\end{list}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
||||
SNStoreData is the wrapper function used to install a DMC data storage
|
||||
command in the Sics interpreter.
|
||||
|
||||
|
||||
\begin{flushleft} \small
|
||||
\begin{minipage}{\linewidth} \label{scrap8}
|
||||
\verb@"nxdata.h"@ {\footnotesize ? }$\equiv$
|
||||
\vspace{-1ex}
|
||||
\begin{list}{}{} \item
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@/*-------------------------------------------------------------------------@\\
|
||||
\mbox{}\verb@ N X D A T A@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ Some routines for handling Nexus data file writing.@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@ Mark Koennecke, April 1997@\\
|
||||
\mbox{}\verb@ @\\
|
||||
\mbox{}\verb@ copyright: see implementation file.@\\
|
||||
\mbox{}\verb@--------------------------------------------------------------------------*/@\\
|
||||
\mbox{}\verb@#ifndef SICSNXDATA@\\
|
||||
\mbox{}\verb@#define SICSNXDATA@\\
|
||||
\mbox{}\verb@@$\langle$Protos {\footnotesize ?, \ldots\ }$\rangle$\verb@ @\\
|
||||
\mbox{}\verb@#endif @\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\end{list}
|
||||
\vspace{-2ex}
|
||||
\end{minipage}\\[4ex]
|
||||
\end{flushleft}
|
89
nxdata.w
89
nxdata.w
@ -1,89 +0,0 @@
|
||||
\subsection{NXdata}
|
||||
NXdata is a module for writing Powder Diffraction Data files. The
|
||||
routines here are somewhat obsolete as they refer to NeXus writing
|
||||
using the standard Napi routines which is quite involved. Usually,
|
||||
NeXus files are written from SICS through the NXDICT aware utility
|
||||
routines in NXUTIL.
|
||||
|
||||
If not stated
|
||||
otherwise, all routines return 1 on successful completion and 0 when an
|
||||
error is detected. Please note, that many of these routines expect to find
|
||||
certain data items in the Sics Interpreter. This implies, that any naming
|
||||
changes in the initialisation file might force changes in here as well.
|
||||
|
||||
@d Protos @{
|
||||
char *SNXMakeFileName(SicsInterp *pSics, SConnection *pCon);
|
||||
@}
|
||||
SNXMakeFileName creates a new filename from the SICS variables SicsDataPath,
|
||||
SicsDataPresript, SicsDataNumber and SicsDataEnding. SicsDataNumber will be
|
||||
incremented as well. The function returns a newly allocate buffer with the
|
||||
assembled filename or NULL on error. Note, that the caller is responsible
|
||||
for freeing the memory associated with the filename afterwards.
|
||||
|
||||
@d Protos @{
|
||||
NXhandle SNXStartFile(SConnection *pCon, SicsInterp *pSics);
|
||||
@}
|
||||
First calls SNXMakeFileName in order to get a new Filename.
|
||||
Then a new Nexus file is
|
||||
created and all the standard headings are filled in: Filename, User,
|
||||
instrument, date etc. This routine also installs an error handler which
|
||||
prints errors to pCon.
|
||||
If successful, the SicsDataNumber is incremented and
|
||||
an NXhandle into the new file is returned. If there is a problem, NULL
|
||||
will be returned. The file returned will be positioned at root level.
|
||||
|
||||
@d Protos @{
|
||||
int SNXStartEntry(NXhandle Nfil, int iNew, SicsInterp *pSics);
|
||||
@}
|
||||
|
||||
@d Protos @{
|
||||
void SNXFormatTime(char *pBuffer, int iBufLen);
|
||||
@}
|
||||
|
||||
SNXFormatTime formats the current system time in a form compatible to the
|
||||
NeXus standard. Input parameters is a Buffer to hold the string and a
|
||||
length of the buffer. Maximum iBufLen characters will be copied to that
|
||||
buffer.
|
||||
|
||||
SNXStartEntry creates a new entry corresponding to iNew in the Nexus file
|
||||
Nfil. SNXStartEntry will position Nfil in this new entry. Any data items
|
||||
labeled as Comment or intent will be written to the file as well.
|
||||
|
||||
|
||||
@d Protos @{
|
||||
int SNFinishFile(NXhandle Nfil);
|
||||
@}
|
||||
|
||||
SNFinishFile will end a Nexus file properly.
|
||||
|
||||
@d Protos @{
|
||||
int SNMakeDMC(SConnection *pCon, SicsInterp *pSics);
|
||||
@}
|
||||
|
||||
SNMakeDMC produces a Nexus DMC data file from the currently valid
|
||||
information. It orchestrates all of the above.
|
||||
|
||||
@d Protos @{
|
||||
int SNStoreDMC(SConnection *pCon, SicsInterp *pSics, void *pData, int argc,
|
||||
char *argv[]);
|
||||
@}
|
||||
SNStoreData is the wrapper function used to install a DMC data storage
|
||||
command in the Sics interpreter.
|
||||
|
||||
|
||||
@o nxdata.h @{
|
||||
/*-------------------------------------------------------------------------
|
||||
N X D A T A
|
||||
|
||||
Some routines for handling Nexus data file writing.
|
||||
|
||||
Mark Koennecke, April 1997
|
||||
|
||||
copyright: see implementation file.
|
||||
--------------------------------------------------------------------------*/
|
||||
#ifndef SICSNXDATA
|
||||
#define SICSNXDATA
|
||||
@< Protos@>
|
||||
#endif
|
||||
|
||||
@}
|
6
ofac.c
6
ofac.c
@ -124,8 +124,6 @@
|
||||
#include "asyncqueue.h"
|
||||
#include "asyncprotocol.h"
|
||||
#include "sicsobj.h"
|
||||
#include "hdbqueue.h"
|
||||
#include "genericcontroller.h"
|
||||
#include "proxy.h"
|
||||
#include "reflist.h"
|
||||
#include "singlex.h"
|
||||
@ -335,10 +333,6 @@ static void InitIniCommands(SicsInterp * pInter, pTaskMan pTask)
|
||||
AddCommand(pInter, "MakeAsyncQueue", AsyncQueueFactory, NULL, NULL);
|
||||
AddCommand(pInter, "MakeSicsObj", InstallSICSOBJ, NULL, NULL);
|
||||
AddCommand(pInter, "DynSicsObj", InstallSICSOBJ, NULL, NULL);
|
||||
/* AddCommand(pInter,"MakeHdbQueue",MakeHDBQueue,NULL,NULL); */
|
||||
AddCommand(pInter, "MakeGenController", GenControllerFactory, NULL,
|
||||
NULL);
|
||||
AddCommand(pInter, "genconfigure", GenControllerConfigure, NULL, NULL);
|
||||
AddCommand(pInter, "MakeProxy", ProxyFactory, NULL, NULL);
|
||||
AddCommand(pInter, "MakeRefList", MakeReflectionList, NULL, NULL);
|
||||
AddCommand(pInter, "MakeSingleX", MakeSingleX, NULL, NULL);
|
||||
|
@ -303,7 +303,13 @@ static int SctMatch(void *data1, void *data2)
|
||||
return a->node == b->node && strcasecmp(a->name, b->name) == 0;
|
||||
}
|
||||
/*
|
||||
* This routine is running the script chain
|
||||
* This routine is running the script chain. It is called repeatedly
|
||||
* with response data from the device serializer (devser). This function
|
||||
* basically:
|
||||
* - Figures out which script to run
|
||||
* - Runs the script
|
||||
* - Based on the result either returns the next string to send to the
|
||||
* device or NULL when the script chain is done with
|
||||
*/
|
||||
static char *SctActionHandler(void *actionData, char *lastReply,
|
||||
int commError)
|
||||
@ -351,7 +357,7 @@ static char *SctActionHandler(void *actionData, char *lastReply,
|
||||
* When this is a followup, we use the content of the
|
||||
* state field as the property storing the next script to
|
||||
* run. If this is the start of a chain this is set to the
|
||||
* data->name which is mortly either read or write
|
||||
* data->name which is mostly either read or write
|
||||
*/
|
||||
state = GetProp(node, controller->node, "state");
|
||||
if (state == NULL || strcasecmp(state, "idle") == 0) {
|
||||
|
621
sel2.c
621
sel2.c
@ -1,621 +0,0 @@
|
||||
/************************************************************************/
|
||||
/* Hahn-Meitner-Institut Berlin */
|
||||
/* Bereich Strukturforschung */
|
||||
/* Abteilung NI / BENSC */
|
||||
/* Glienicker Strasse 100 */
|
||||
/* D-14109 Berlin (Wannsee) */
|
||||
/* Software:K. Emmelmann, Tel.(030)8062-2588, Mail: klaus@dvwbs5.hmi.de */
|
||||
/************************************************************************/
|
||||
/* Datei: SEL.C */
|
||||
/* Teil von: KWS.C */
|
||||
/* Anwendung bei: V4 - KWS */
|
||||
/* Titel: Treiberprogramm fuer Geschwindigkeitsselektor DORNIER */
|
||||
/* Version: 1.0 vom: 30.1.96 */
|
||||
/************************************************************************/
|
||||
/*
|
||||
Legende
|
||||
=======
|
||||
|
||||
30.1.96 Emmelmann Implementierung
|
||||
1.2.96 Emmelmann Statusdekodierung eingebaut
|
||||
27.2.96 Emmelmann Strom wird auch im Status geliefert
|
||||
|
||||
|
||||
Das Handbuch sagt Empfangsterminator ist Linefeed.
|
||||
|
||||
|
||||
Jeder Befehl erzeugt ein Echo; argumentlose Befehle werden im Echo
|
||||
zusaetzlich mit einer Zahl versehen, deren Bedeutung unbekannt ist.
|
||||
|
||||
|
||||
FEHLERMELDUNGEN, die bekannt sind:
|
||||
****************************************
|
||||
|
||||
1. Solldrehzahl zu klein !
|
||||
2. Solldrehzahl zu gross !
|
||||
3. derzeit keine Ausfuehrung moeglich !
|
||||
4. Solldrehzahl in einem kritischen Bereich
|
||||
- return to m
|
||||
5. HOCHFAHREN 1
|
||||
6.
|
||||
|
||||
zu 3: Abfrage der Istgeschwindigkeit ist waehrend des Hochfahrens aus dem
|
||||
Stillstand nur ueber Lesen des Gesamtstatus moeglich
|
||||
zu 4: es gibt verbotene Geschwindigkeitsbereiche
|
||||
zu 5: beim Uebergang von Stop in den gestarteten Zustand
|
||||
|
||||
Zeitliches Protokollverhalten
|
||||
-----------------------------
|
||||
Wird ein Befehl bearbeitet, werden alle weiteren ueber die serielle
|
||||
Schnittstelle einlaufenden Befehle ignoriert - auch nicht gepuffert !
|
||||
|
||||
Max. Befahlsrate: 1 Befehl / 5 Sekunden
|
||||
|
||||
Geraete-Verhalten
|
||||
-----------------
|
||||
Der Startbefehl faehrt den Selektor auf die Minimalgeschwindigkeit (3100U/min)
|
||||
|
||||
Das Protokoll: fuer jeden Befehl erzeugt der Selektor-PC ein Echo !
|
||||
|
||||
Host -> Selektor
|
||||
------------------------
|
||||
REM (disabled) Remote-Betrieb einschalten
|
||||
Rueckmeldung: ENABLED / Host nicht betriebsbereit!
|
||||
|
||||
TTY (disabled) Local-Betrieb einschalten
|
||||
Rueckmeldung: DISABLED
|
||||
|
||||
??? Sende Status (Status ist nicht fest und geht von der
|
||||
Interpretation der Kennworte aus !)
|
||||
|
||||
TIM (disabled) Setzen des Zeitintervalles zur Time-Out-Ueberwachung des PCs
|
||||
????
|
||||
|
||||
SST Start des Selektors und Ausregeln der Drehzahl (Nur wenn der
|
||||
Selektor steht !); liefert als Rueckmeldung die Solldrehzahl
|
||||
|
||||
SDR nnnnn Vorgabe einer Soll-Drehzahl und geregelten Betrieb einschalten.
|
||||
3100 => nnnnn <=28300 U/min; liegt der Wert in einem kritischen
|
||||
Bereich (geht aus Setup-Menue hervor), kommt eine entsprechende
|
||||
Rueckmeldung
|
||||
|
||||
FDR Sende die Solldrehzahl (Format 'RPM n')
|
||||
|
||||
STB Leerlauf ohne Regelung
|
||||
|
||||
BRE Beginne eine Verlustleistungsmessung - ist bei Statusabruf
|
||||
lesbar, wenn dort die Betriebsart regeln erscheint !
|
||||
|
||||
HAL Bremse Selektor bis zum Stillstand ab (unterhalb 3000 U/min.)
|
||||
|
||||
*/
|
||||
#include stdio.h
|
||||
#include descrip.h
|
||||
#include iodef.h
|
||||
#include errno.h
|
||||
#include lnmdef.h
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE !FALSE
|
||||
|
||||
#define OK 0L
|
||||
#define NOT_OK !OK
|
||||
|
||||
#define LIMIT_U 3100 /* niedrigste Drehzahl */
|
||||
#define LIMIT_O 28300
|
||||
|
||||
/* Verbotene Drehzahlbereiche (Resonanzgefahr) */
|
||||
|
||||
#define RESONANZ_1U 3648
|
||||
#define RESONANZ_1O 4552
|
||||
#define RESONANZ_2U 5248
|
||||
#define RESONANZ_2O 6449
|
||||
#define RESONANZ_3U 9148
|
||||
#define RESONANZ_3O 9949
|
||||
|
||||
#define TOK_BUF_L 25
|
||||
|
||||
#define SELE_LUN 0
|
||||
|
||||
extern FILE *fs;
|
||||
|
||||
static short chan_s = 6;
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
long select_setup()
|
||||
{
|
||||
register rc;
|
||||
$DESCRIPTOR(dev_descr, "TXA1:");
|
||||
chan_s = SELE_LUN;
|
||||
if ((rc = sys$assign(&dev_descr, &chan_s, NULL, NULL)) != 1) {
|
||||
printf("Error in Selector_SETUP: Ret = %d\n", rc);
|
||||
return (NOT_OK);
|
||||
}
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Function liest ueberprueft das Befehlsecho */
|
||||
long sele_test_echo(cmd, lng)
|
||||
char *cmd[];
|
||||
int lng;
|
||||
{
|
||||
char echo[80];
|
||||
if (sele_read(&echo) != OK)
|
||||
return (NOT_OK);
|
||||
if (strncmp(&echo, cmd, lng) != 0) {
|
||||
printf("Selector:protocol error%s\n", echo);
|
||||
return (NOT_OK);
|
||||
} else
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Function prueft die Anzahl der sich im Typeahead-Buffer befindenden Bytes
|
||||
und liefert das naechste dort anstehende Zeichen, jedoch ohne es
|
||||
aus dem Puffer zu entnehmen.
|
||||
*/
|
||||
long tst_buf_s(bt)
|
||||
int *bt;
|
||||
{
|
||||
int bytes;
|
||||
register rc;
|
||||
struct {
|
||||
unsigned short status, bytes;
|
||||
int pid;
|
||||
} iosb;
|
||||
if ((rc = sys$qiow(NULL, chan_s, IO$_SENSEMODE | IO$M_TYPEAHDCNT, &iosb,
|
||||
NULL, NULL, &bytes, NULL, NULL, NULL, NULL,
|
||||
NULL)) != 1) {
|
||||
print_error(fs, "Error in QIOW");
|
||||
return (NOT_OK);
|
||||
}
|
||||
/**ch = (bytes >> 16) & 0xff;*/
|
||||
*bt = bytes & 0xffff;
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
long sele_read(message)
|
||||
char *message;
|
||||
{
|
||||
char char_l[8], *ptr;
|
||||
register rc;
|
||||
struct {
|
||||
unsigned short status, bytes;
|
||||
int pid;
|
||||
} iosb;
|
||||
ptr = message;
|
||||
for (;;) {
|
||||
if ((rc = sys$qiow(NULL, chan_s, IO$_READVBLK | IO$M_NOECHO,
|
||||
&iosb, NULL,
|
||||
NULL, char_l, 1, NULL, NULL, NULL, NULL)) != 1) {
|
||||
printf("Error in QIOW, READ_MESS: %d\n", rc);
|
||||
return (NOT_OK);
|
||||
}
|
||||
*ptr = char_l[0];
|
||||
/* Terminator (linefeed) ? */
|
||||
ptr++;
|
||||
if (char_l[0] == '\n')
|
||||
break;
|
||||
}
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Pruefe ob der Selektor eine Fehlermeldung erzeugt hat und gib sie aus */
|
||||
|
||||
long select_error_msg(err)
|
||||
long *err;
|
||||
{
|
||||
char chr[10], msg[80];
|
||||
float waiti = 3.0; /* Selektor PC hat 3 Sekunden Reaktionszeit !! */
|
||||
|
||||
/* Warte ein wenig - es koennte auf den Befehl hin eine Fehlermeldung erscheinen */
|
||||
lib$wait(&waiti);
|
||||
|
||||
/* Es koennen auch mehrere Zeilen sein */
|
||||
*err = FALSE;
|
||||
for (;;) {
|
||||
if (tst_buf_s(&chr) != OK)
|
||||
return (NOT_OK);
|
||||
if (chr[0] != NULL) {
|
||||
if (sele_read(&msg) != OK)
|
||||
return (NOT_OK);
|
||||
printf("Selektor failure:");
|
||||
printf("%s\n\7", msg);
|
||||
*err = TRUE;
|
||||
} else
|
||||
return (OK);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
long sele_write(message)
|
||||
char message[];
|
||||
{
|
||||
char msg[80];
|
||||
long err;
|
||||
register rc;
|
||||
struct {
|
||||
unsigned short status, bytes;
|
||||
int pid;
|
||||
} iosb;
|
||||
|
||||
if (select_error_msg(&err) != OK)
|
||||
return (NOT_OK);
|
||||
if (err == TRUE)
|
||||
return (NOT_OK);
|
||||
|
||||
if ((rc = sys$qiow(NULL, chan_s, IO$_WRITEVBLK, &iosb, NULL, NULL,
|
||||
message, strlen(message), NULL, NULL, NULL,
|
||||
NULL)) != 1) {
|
||||
printf("Error in QIOW: %d\n", rc);
|
||||
return (NOT_OK);
|
||||
}
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/*
|
||||
Ein-/ Ausschalten von Stoerungsmeldungen vom Selektor an den Host
|
||||
Diese Funktion ist z.Z. nur vom Selektor-PC aktivierbar
|
||||
*/
|
||||
long select_msg(tim)
|
||||
long tim;
|
||||
{
|
||||
int sts;
|
||||
long err;
|
||||
char cmd[20] = "TIM ";
|
||||
snprintf(&cmd + 4,sizeof(&cmd + 4)-1, "%5u\0", tim);
|
||||
sts = sele_write(cmd);
|
||||
if (sele_test_echo(&cmd, 3) != OK)
|
||||
lib$stop(-1);
|
||||
if (select_error_msg(&err) != OK)
|
||||
return (NOT_OK);
|
||||
if (err == TRUE)
|
||||
return (NOT_OK);
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Einschaltung der Fremdsteuerung des Selektors
|
||||
Diese Funktion ist z.Z. nur vom Selektor-PC aktivierbar
|
||||
*/
|
||||
long select_remote()
|
||||
{
|
||||
int sts;
|
||||
long err;
|
||||
char cmd[] = "REM";
|
||||
sts = sele_write(cmd);
|
||||
if (sele_test_echo(&cmd, 3) != OK)
|
||||
lib$stop(-1);
|
||||
if (select_error_msg(&err) != OK)
|
||||
return (NOT_OK);
|
||||
if (err == TRUE)
|
||||
return (NOT_OK);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Ausschaltung der Fremdsteuerung des Selektors -
|
||||
ein Steuerung kann dann nur noch ueber den PC des Geraetes
|
||||
erfolgen.
|
||||
Diese Funktion ist z.Z. nur vom Selektor-PC aktivierbar
|
||||
*/
|
||||
long select_local()
|
||||
{
|
||||
int sts;
|
||||
long err;
|
||||
char cmd[] = "TTY";
|
||||
sts = sele_write(cmd);
|
||||
if (sele_test_echo(&cmd, 3) != OK)
|
||||
lib$stop(-1);
|
||||
if (select_error_msg(&err) != OK)
|
||||
return (NOT_OK);
|
||||
if (err == TRUE)
|
||||
return (NOT_OK);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Starten des Selektors nach Stillstand auf die Minimaldrehzahl
|
||||
*/
|
||||
long select_start()
|
||||
{
|
||||
int sts;
|
||||
long err;
|
||||
char cmd[] = "SST";
|
||||
sts = sele_write(cmd);
|
||||
if (sele_test_echo(&cmd, 3) != OK)
|
||||
lib$stop(-1);
|
||||
if (select_error_msg(&err) != OK)
|
||||
return (NOT_OK);
|
||||
if (err == TRUE)
|
||||
return (NOT_OK);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Bremsen des Selektors bis zum Stillstand; eine
|
||||
Drehzahlanzeige unterhalb 3000 U/min ist nicht moeglich.
|
||||
*/
|
||||
long select_stop()
|
||||
{
|
||||
int sts;
|
||||
long err;
|
||||
char cmd[] = "HAL";
|
||||
sts = sele_write(cmd);
|
||||
if (sele_test_echo(&cmd, 3) != OK)
|
||||
lib$stop(-1);
|
||||
if (select_error_msg(&err) != OK)
|
||||
return (NOT_OK);
|
||||
if (err == TRUE)
|
||||
return (NOT_OK);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Einschalten des geregelten Betriebes mit dem Setzen eines Sollwertes
|
||||
der Drehzahl.
|
||||
Aenderungen werden spontan uebernommen und ausgefuehrt.
|
||||
Neben dem absoluten Minimum und Maximum existieren verbotene
|
||||
Drehzahlbereiche, die z.Z. noch nicht exakt bekannt sind.
|
||||
*/
|
||||
long select_set_rpm(rpm)
|
||||
int rpm;
|
||||
{
|
||||
int sts;
|
||||
long err;
|
||||
char cmd[] = "SDR", s_dat[10] = "SDR 00000";
|
||||
if ((rpm < LIMIT_U) || (rpm > LIMIT_O)) {
|
||||
print_error(fs, "nominal value out of allowed range");
|
||||
return;
|
||||
}
|
||||
/* Resonanzbereiche sind auch verboten */
|
||||
if (((rpm >= RESONANZ_1U) && (rpm <= RESONANZ_1O)) ||
|
||||
((rpm >= RESONANZ_2U) && (rpm <= RESONANZ_2O)) ||
|
||||
((rpm >= RESONANZ_3U) && (rpm <= RESONANZ_3O))) {
|
||||
print_error(fs, "nominal value within inhibited range");
|
||||
return;
|
||||
}
|
||||
snprintf(&s_dat + 4,sizeof(&s_dat + 4)-1, "%5u", rpm);
|
||||
sts = sele_write(s_dat);
|
||||
if (sele_test_echo(&cmd, 3) != OK)
|
||||
lib$stop(-1);
|
||||
if (select_error_msg(&err) != OK)
|
||||
return (NOT_OK);
|
||||
if (err == TRUE)
|
||||
return (NOT_OK);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Leerlauf des Selektors einschalten; weder Antrieb noch
|
||||
Verzoegerung erfolgen - eine anschliessende Abbremsung oder
|
||||
ein Uebergang zum geregelten Betrieb ist moeglich.
|
||||
*/
|
||||
long select_set_idle()
|
||||
{
|
||||
int sts;
|
||||
long err;
|
||||
char cmd[] = "STB";
|
||||
sts = sele_write(cmd);
|
||||
if (sele_test_echo(&cmd, 3) != OK)
|
||||
lib$stop(-1);
|
||||
if (select_error_msg(&err) != OK)
|
||||
return (NOT_OK);
|
||||
if (err == TRUE)
|
||||
return (NOT_OK);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Starten der Messung der elektrischen Verlustleistung des
|
||||
Selektors. Anscheinend wird waehrend der Zeit die
|
||||
Regelung deaktiviert.
|
||||
Nach Abschluss der Messung erfolgt ein Uebergang in den\
|
||||
geregelten Berieb.
|
||||
Das Messergebnis wird in den Statusinformationsblock eingetragen.
|
||||
*/
|
||||
long select_read_power()
|
||||
{
|
||||
int sts;
|
||||
long err;
|
||||
char cmd[] = "BRE";
|
||||
sts = sele_write(cmd);
|
||||
if (sele_test_echo(&cmd, 3) != OK)
|
||||
lib$stop(-1);
|
||||
if (select_error_msg(&err) != OK)
|
||||
return (NOT_OK);
|
||||
if (err == TRUE)
|
||||
return (NOT_OK);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Lesen der aktuellen Drehzahl des Selektors */
|
||||
long select_read_rpm(rpm)
|
||||
int *rpm;
|
||||
{
|
||||
int sts, tmp;
|
||||
long err;
|
||||
char status[80], cmd[] = "FDR";
|
||||
sts = sele_write(cmd);
|
||||
if (sele_test_echo(&cmd, 3) != OK)
|
||||
lib$stop(-1);
|
||||
|
||||
sts = sele_read(&status);
|
||||
sscanf(&status + 4, "%d", &tmp);
|
||||
*rpm = tmp;
|
||||
if (select_error_msg(&err) != OK)
|
||||
return (NOT_OK);
|
||||
if (err == TRUE)
|
||||
return (NOT_OK);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Auslesen des kompletten Statusblockes des Selektors.
|
||||
Der Informationseintrag 'Verlustleistung' ist anscheinend nur dann
|
||||
aktuell, wenn zuvor eine Verlustleistungsmessung aktiviert wurde.
|
||||
Argumente:
|
||||
rm = Betriebsstatus
|
||||
[REG == regelnd]
|
||||
[STB == im Leerlauf]
|
||||
[BRE == bremsend]
|
||||
nom_rpm = Soll der Drehzahl (U/min)
|
||||
cur_rpm = Ist der Drehzahl (U/min)
|
||||
pwr = Verlustleistung (W)
|
||||
curr = elektr. Stomstaerke (A)
|
||||
rot_temp= Temperatur des Rotors (C)
|
||||
cont_temp= Temperatur des Gehaeuses (C)
|
||||
inl_temp= Temperatur Kuehlwasser-Einlass
|
||||
outl_temp= Temperatur Kuehlwasser-Abfluss
|
||||
cool_wat= Kuehlwasser-Durchfluss (l/min)
|
||||
vacuum = Betriebsvakuum (mbar)
|
||||
accel = Rotationsbeschleunigung (g)
|
||||
komm = Kommunikation zwischen Selektor-PC und Host
|
||||
'ENABLED' oder "DISABLED'
|
||||
dat = Tagesdatum dd.m.yyyy
|
||||
tim = Tageszeit hh.mm.s
|
||||
|
||||
*/
|
||||
long select_read_status(rm, nom_rpm, cur_rpm, pwr, curr, rot_temp,
|
||||
cont_temp, inl_temp, outl_temp, cool_wat, vacuum,
|
||||
accel, komm, dat, tim)
|
||||
char *rm[];
|
||||
int *nom_rpm, *cur_rpm, *pwr, *rot_temp, *cont_temp, *inl_temp, *outl_temp;
|
||||
float *cool_wat, *vacuum, *accel, *curr;
|
||||
char *dat[], *tim[];
|
||||
short *komm;
|
||||
{
|
||||
int cnt, key_id, sl, sts;
|
||||
long err;
|
||||
char ena_str[] = "ENABLED";
|
||||
char dis_str[] = "DISABLED";
|
||||
char keys[15][9] = {
|
||||
"Status:\0 ",
|
||||
"S_DREH:\0 ",
|
||||
"I_DREH:\0 ",
|
||||
"P_VERL:\0 ",
|
||||
"STROM:\0 ",
|
||||
"T_ROT:\0 ",
|
||||
"T_GEH:\0 ",
|
||||
"T_VOR:\0 ",
|
||||
"T_RUECK:\0",
|
||||
"DURCHFL:\0",
|
||||
"VAKUUM:\0 ",
|
||||
"BESCHL:\0 ",
|
||||
"KOM: \0 ",
|
||||
"DATE: \0 ",
|
||||
"TIME: \0 "
|
||||
};
|
||||
|
||||
char tok_buf[TOK_BUF_L], *ptr_token, *ptr_src, *ptr, tok_c[] = "/\0";
|
||||
|
||||
char status[255], cmd[] = "???";
|
||||
|
||||
if (sele_write(cmd) != OK)
|
||||
return (NOT_OK);
|
||||
|
||||
if (sele_test_echo(&cmd, 3) == NOT_OK)
|
||||
lib$stop(-1);
|
||||
|
||||
if (sele_read(&status) != OK)
|
||||
return (NOT_OK); /* Und nun der Status */
|
||||
ptr_src = &status;
|
||||
for (;;) {
|
||||
/* Lies Zeichenfolge bis zum naechsten Trennzeichen '/' */
|
||||
ptr_token = strtok(ptr_src, &tok_c);
|
||||
ptr_src = NULL; /* fuer die weitere Suche notwendig */
|
||||
if (ptr_token == NULL)
|
||||
break;
|
||||
strcpy(&tok_buf, ptr_token);
|
||||
|
||||
for (key_id = 0; key_id <= 14; key_id++) {
|
||||
/* Ist das Schluesselwort enthalten ? */
|
||||
sl = strlen(keys[key_id]);
|
||||
if (strncmp(&keys[key_id][0], &tok_buf, sl) == NULL) {
|
||||
/* Schiebe das Schluesselwort raus */
|
||||
for (cnt = 0; cnt + sl < TOK_BUF_L; cnt++)
|
||||
tok_buf[cnt] = tok_buf[cnt + sl];
|
||||
switch (key_id) {
|
||||
case 0:
|
||||
{
|
||||
ptr = rm;
|
||||
strcpy(ptr, &tok_buf);
|
||||
break;
|
||||
}
|
||||
case 1:{
|
||||
sscanf(&tok_buf, "%d", nom_rpm);
|
||||
break;
|
||||
}
|
||||
case 2:{
|
||||
sscanf(&tok_buf, "%d", cur_rpm);
|
||||
break;
|
||||
}
|
||||
case 3:{
|
||||
sscanf(&tok_buf, "%d", pwr);
|
||||
break;
|
||||
}
|
||||
case 4:{
|
||||
sscanf(&tok_buf, "%f", curr);
|
||||
break;
|
||||
}
|
||||
case 5:{
|
||||
sscanf(&tok_buf, "%d", rot_temp);
|
||||
break;
|
||||
}
|
||||
case 6:{
|
||||
sscanf(&tok_buf, "%d", cont_temp);
|
||||
break;
|
||||
}
|
||||
case 7:{
|
||||
sscanf(&tok_buf, "%d", inl_temp);
|
||||
break;
|
||||
}
|
||||
case 8:{
|
||||
sscanf(&tok_buf, "%d", outl_temp);
|
||||
break;
|
||||
}
|
||||
case 9:{
|
||||
sscanf(&tok_buf, "%f", cool_wat);
|
||||
break;
|
||||
}
|
||||
case 10:{
|
||||
sscanf(&tok_buf, "%f", vacuum);
|
||||
break;
|
||||
}
|
||||
case 11:{
|
||||
sscanf(&tok_buf, "%f", accel);
|
||||
break;
|
||||
}
|
||||
case 12:
|
||||
{
|
||||
if (strcmp(&tok_buf, &ena_str) == NULL) {
|
||||
*komm = TRUE;
|
||||
break;
|
||||
}
|
||||
if (strcmp(&tok_buf, &dis_str) == NULL) {
|
||||
*komm = FALSE;
|
||||
break;
|
||||
}
|
||||
printf("Invalid Communication value");
|
||||
break;
|
||||
}
|
||||
case 13:
|
||||
{
|
||||
ptr = dat;
|
||||
strcpy(ptr, &tok_buf);
|
||||
break;
|
||||
}
|
||||
case 14:
|
||||
{
|
||||
ptr = tim;
|
||||
strcpy(ptr, &tok_buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (select_error_msg(&err) != OK)
|
||||
return (NOT_OK);
|
||||
if (err == TRUE)
|
||||
return (NOT_OK);
|
||||
return (OK);
|
||||
}
|
@ -10,3 +10,4 @@
|
||||
MFLAGS=-f makefile_linux$(DUMMY)
|
||||
|
||||
HDFROOT=/afs/psi.ch/project/sinq/sl5
|
||||
TCLINC=.
|
Reference in New Issue
Block a user