- Added missing files to split directories
This commit is contained in:
586
ecbcounter.c
Normal file
586
ecbcounter.c
Normal file
@ -0,0 +1,586 @@
|
|||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
This is a single counter implemented on top of the Risoe ECB electronic
|
||||||
|
|
||||||
|
copyright: see file COPYRIGHT
|
||||||
|
|
||||||
|
Mark Koennecke, January-February 2003
|
||||||
|
---------------------------------------------------------------------------*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <tcl.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fortify.h>
|
||||||
|
#include <sics.h>
|
||||||
|
#include <status.h>
|
||||||
|
#include "ecb.h"
|
||||||
|
#include <countdriv.h>
|
||||||
|
|
||||||
|
/*------------------ our private data structure ------------------------*/
|
||||||
|
typedef struct {
|
||||||
|
pECB ecb; /* the ECB system we talk to */
|
||||||
|
unsigned char prescaler[8]; /* an array for the prescaler values */
|
||||||
|
int tfreq; /* timer frequency */
|
||||||
|
unsigned char control; /* marks the control monitor */
|
||||||
|
int state; /* current counting state */
|
||||||
|
}ECBCounter, *pECBCounter;
|
||||||
|
|
||||||
|
/*----------------- private defines ------------------------------------*/
|
||||||
|
#define STFRD 137
|
||||||
|
#define STREAD 138
|
||||||
|
#define STOPS 136
|
||||||
|
#define STCLEA 134
|
||||||
|
#define PRELOA 139
|
||||||
|
#define STLOAD 156
|
||||||
|
#define STCPRE 133
|
||||||
|
#define STARTS 135
|
||||||
|
#define SPCSTA 169
|
||||||
|
|
||||||
|
/*------------------ state codes --------------------------------------*/
|
||||||
|
#define IDLE 0
|
||||||
|
#define COUNT 2
|
||||||
|
#define NOBEAM 3
|
||||||
|
/*--------------------------------------------------------------------*/
|
||||||
|
#define MAX_COUNT 4294967295.0
|
||||||
|
/*------------------ error codes --------------------------------------*/
|
||||||
|
#define COMMERROR -300
|
||||||
|
#define TOMANYCOUNTS -301
|
||||||
|
#define NOSEND -302
|
||||||
|
#define INVALIDCOUNTER -304
|
||||||
|
#define INVALIDPRESCALER -305
|
||||||
|
#define BADFREQ -306
|
||||||
|
/*======================================================================*/
|
||||||
|
static int readScaler(pECBCounter pPriv, int scaler, int *count){
|
||||||
|
int status;
|
||||||
|
Z80_reg in, out;
|
||||||
|
Ecb_pack data;
|
||||||
|
|
||||||
|
in.c = (unsigned char)scaler;
|
||||||
|
status = ecbExecute(pPriv->ecb,STREAD,in,&out);
|
||||||
|
if(status != 1){
|
||||||
|
return COMMERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.b.byt3 = out.c;
|
||||||
|
data.b.byt2 = out.b;
|
||||||
|
data.b.byt1 = out.d;
|
||||||
|
data.b.byt0 = out.e;
|
||||||
|
if(scaler == 0){
|
||||||
|
*count = data.result/pPriv->tfreq;
|
||||||
|
} else {
|
||||||
|
*count = data.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------*/
|
||||||
|
static int check4Beam(struct __COUNTER *pCter, int *beam){
|
||||||
|
Z80_reg in, out;
|
||||||
|
pECBCounter self = NULL;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
self = (pECBCounter)pCter->pData;
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
in.c = 1;
|
||||||
|
status = ecbExecute(self->ecb,SPCSTA,in,&out);
|
||||||
|
if(status != 1){
|
||||||
|
pCter->iErrorCode = COMMERROR;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
*beam = (int)out.d;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*----------------------------------------------------------------------*/
|
||||||
|
static int stopScalers(pECBCounter self){
|
||||||
|
int status;
|
||||||
|
Z80_reg in, out;
|
||||||
|
|
||||||
|
status = ecbExecute(self->ecb,STOPS,in,&out);
|
||||||
|
if(status != 1){
|
||||||
|
return COMMERROR;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*========================================================================
|
||||||
|
These two functions currently rely on the idea that the ECB stops
|
||||||
|
and starts without clearing counters in between. The sequence of
|
||||||
|
things necessary to start it, suggests this. If this is not the case then
|
||||||
|
this will not work.
|
||||||
|
===========================================================================*/
|
||||||
|
static int ECBPause(struct __COUNTER *self){
|
||||||
|
int status;
|
||||||
|
pECBCounter pPriv = NULL;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pPriv = (pECBCounter)self->pData;
|
||||||
|
assert(pPriv);
|
||||||
|
|
||||||
|
if((status = stopScalers(pPriv)) <= 0){
|
||||||
|
self->iErrorCode = status;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
return OKOK;
|
||||||
|
}
|
||||||
|
/*=======================================================================*/
|
||||||
|
static int ECBContinue(struct __COUNTER *self){
|
||||||
|
int status;
|
||||||
|
pECBCounter pPriv = NULL;
|
||||||
|
Z80_reg in, out;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pPriv = (pECBCounter)self->pData;
|
||||||
|
assert(pPriv);
|
||||||
|
|
||||||
|
status = ecbExecute(pPriv->ecb,STARTS,in,&out);
|
||||||
|
if(status != 1){
|
||||||
|
self->iErrorCode = status;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OKOK;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
static int ECBGetStatus(struct __COUNTER *self, float *fControl){
|
||||||
|
pECBCounter pPriv = (pECBCounter)self->pData;
|
||||||
|
int status, result, scaler;
|
||||||
|
Z80_reg in, out;
|
||||||
|
int count, beam;
|
||||||
|
|
||||||
|
assert(pPriv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
This can happen after a stop
|
||||||
|
*/
|
||||||
|
if(pPriv->state == IDLE){
|
||||||
|
return HWIdle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
read status bit
|
||||||
|
*/
|
||||||
|
status = ecbExecute(pPriv->ecb,STFRD,in,&out);
|
||||||
|
if(status != 1){
|
||||||
|
self->iErrorCode = COMMERROR;
|
||||||
|
pPriv->state = IDLE;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
read beam status
|
||||||
|
*/
|
||||||
|
status = check4Beam(self,&beam);
|
||||||
|
if(status != 1){
|
||||||
|
self->iErrorCode = COMMERROR;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
beam &= 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
sophisticated logic in order to keep track of the various states
|
||||||
|
the thing can be in. Complicated by the fact that the status becomes
|
||||||
|
idle (out.d = 0) when the measurement is paused due to the lack of
|
||||||
|
beam.
|
||||||
|
*/
|
||||||
|
if(pPriv->state == COUNT && beam == 1){
|
||||||
|
ECBPause(self);
|
||||||
|
pPriv->state = NOBEAM;
|
||||||
|
SetStatus(eOutOfBeam);
|
||||||
|
result = HWNoBeam;
|
||||||
|
}
|
||||||
|
if(pPriv->state == NOBEAM && beam == 0){
|
||||||
|
ECBContinue(self);
|
||||||
|
pPriv->state = COUNT;
|
||||||
|
SetStatus(eCounting);
|
||||||
|
return HWBusy;
|
||||||
|
}
|
||||||
|
if(pPriv->state == NOBEAM && beam == 1){
|
||||||
|
return HWNoBeam;
|
||||||
|
}
|
||||||
|
if(out.d == 0 && pPriv->state == COUNT){
|
||||||
|
result = HWIdle;
|
||||||
|
pPriv->state = IDLE;
|
||||||
|
} else {
|
||||||
|
result = HWBusy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
select which scaler to read
|
||||||
|
*/
|
||||||
|
if(self->eMode == eTimer){
|
||||||
|
scaler = 0;
|
||||||
|
}else {
|
||||||
|
scaler = pPriv->control;
|
||||||
|
}
|
||||||
|
|
||||||
|
readScaler(pPriv,scaler,&count);
|
||||||
|
/*
|
||||||
|
ignore errors on this one
|
||||||
|
*/
|
||||||
|
*fControl = (float)count;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/*=====================================================================*/
|
||||||
|
static int clearScalers(pECBCounter self){
|
||||||
|
int status;
|
||||||
|
Z80_reg in, out;
|
||||||
|
|
||||||
|
status = ecbExecute(self->ecb,STCLEA,in,&out);
|
||||||
|
if(status != 1){
|
||||||
|
return COMMERROR;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*----------------------------------------------------------------------*/
|
||||||
|
static int loadPrescalers(pECBCounter self){
|
||||||
|
Z80_reg in, out;
|
||||||
|
int status, i;
|
||||||
|
|
||||||
|
for(i = 0; i < 8; i++){
|
||||||
|
in.c = (unsigned char)i;
|
||||||
|
in.d = self->prescaler[i];
|
||||||
|
status = ecbExecute(self->ecb,PRELOA,in,&out);
|
||||||
|
if(status != 1){
|
||||||
|
return COMMERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*----------------------------------------------------------------------*/
|
||||||
|
static int loadPreset(pECBCounter self, int preset, unsigned char control){
|
||||||
|
Z80_reg in, out;
|
||||||
|
Ecb_pack data;
|
||||||
|
int status, i;
|
||||||
|
|
||||||
|
data.result = preset;
|
||||||
|
|
||||||
|
in.c = data.b.byt3;
|
||||||
|
in.b = data.b.byt2;
|
||||||
|
in.e = data.b.byt1;
|
||||||
|
in.d = data.b.byt0;
|
||||||
|
status = ecbExecute(self->ecb,STLOAD,in,&out);
|
||||||
|
if(status != 1){
|
||||||
|
return COMMERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
in.b = data.b.byt2;
|
||||||
|
in.e = data.b.byt1;
|
||||||
|
in.d = data.b.byt0;
|
||||||
|
in.c = 4*control;
|
||||||
|
status = ecbExecute(self->ecb,STCPRE,in,&out);
|
||||||
|
if(status != 1){
|
||||||
|
return COMMERROR;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
static int ECBStart(struct __COUNTER *self){
|
||||||
|
pECBCounter pPriv = NULL;
|
||||||
|
int preset, status, controlUnit;
|
||||||
|
Z80_reg in, out;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pPriv = (pECBCounter)self->pData;
|
||||||
|
assert(pPriv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
check if the preset is permissible
|
||||||
|
*/
|
||||||
|
preset = (int)rint(self->fPreset);
|
||||||
|
if(preset > MAX_COUNT){
|
||||||
|
self->iErrorCode = TOMANYCOUNTS;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
if(self->eMode == eTimer){
|
||||||
|
controlUnit = 0;
|
||||||
|
preset *= pPriv->tfreq;
|
||||||
|
if(preset > MAX_COUNT){
|
||||||
|
self->iErrorCode = TOMANYCOUNTS;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
controlUnit = pPriv->control;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((status = stopScalers(pPriv)) <= 0){
|
||||||
|
self->iErrorCode = status;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((status = clearScalers(pPriv)) <= 0){
|
||||||
|
self->iErrorCode = status;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((status = loadPrescalers(pPriv)) <= 0){
|
||||||
|
self->iErrorCode = status;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((status = loadPreset(pPriv, preset,(unsigned char)controlUnit)) <= 0){
|
||||||
|
self->iErrorCode = status;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = ecbExecute(pPriv->ecb,STARTS,in,&out);
|
||||||
|
if(status != 1){
|
||||||
|
self->iErrorCode = status;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
|
||||||
|
pPriv->state = COUNT;
|
||||||
|
return OKOK;
|
||||||
|
}
|
||||||
|
/*=======================================================================*/
|
||||||
|
static int ECBHalt(struct __COUNTER *self){
|
||||||
|
int status;
|
||||||
|
pECBCounter pPriv = NULL;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pPriv = (pECBCounter)self->pData;
|
||||||
|
assert(pPriv);
|
||||||
|
|
||||||
|
pPriv->state = IDLE;
|
||||||
|
if((status = stopScalers(pPriv)) <= 0){
|
||||||
|
self->iErrorCode = status;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
return OKOK;
|
||||||
|
}
|
||||||
|
/*=======================================================================*/
|
||||||
|
static int ECBTransfer(struct __COUNTER *self){
|
||||||
|
int status, count, i;
|
||||||
|
pECBCounter pPriv = NULL;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pPriv = (pECBCounter)self->pData;
|
||||||
|
assert(pPriv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
read time
|
||||||
|
*/
|
||||||
|
status = readScaler(pPriv,0,&count);
|
||||||
|
if(status <= 0){
|
||||||
|
self->iErrorCode = COMMERROR;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
self->fTime = (float)count;
|
||||||
|
|
||||||
|
/*
|
||||||
|
read other scalers
|
||||||
|
*/
|
||||||
|
for(i = 1; i < 8; i++){
|
||||||
|
status = readScaler(pPriv,i,&count);
|
||||||
|
if(status <= 0){
|
||||||
|
self->iErrorCode = COMMERROR;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
self->lCounts[i-1] = count;
|
||||||
|
}
|
||||||
|
return OKOK;
|
||||||
|
}
|
||||||
|
/*======================================================================*/
|
||||||
|
static int ECBGetError(struct __COUNTER *self, int *iCode,
|
||||||
|
char *errorText, int errlen){
|
||||||
|
char pBueffel[132];
|
||||||
|
|
||||||
|
*iCode = self->iErrorCode;
|
||||||
|
switch(self->iErrorCode){
|
||||||
|
case COMMERROR:
|
||||||
|
strncpy(errorText,"Communication error with ECB",errlen);
|
||||||
|
break;
|
||||||
|
case TOMANYCOUNTS:
|
||||||
|
strncpy(errorText,"Preset is to high!",errlen);
|
||||||
|
break;
|
||||||
|
case NOSEND:
|
||||||
|
strncpy(errorText,"Cannot send naked data to ECB",errlen);
|
||||||
|
break;
|
||||||
|
case UNKNOWNPAR:
|
||||||
|
strncpy(errorText,"parameter unknown",errlen);
|
||||||
|
break;
|
||||||
|
case INVALIDCOUNTER:
|
||||||
|
strncpy(errorText,"Invalid counter number requested, 0-7 allowed",
|
||||||
|
errlen);
|
||||||
|
break;
|
||||||
|
case INVALIDPRESCALER:
|
||||||
|
strncpy(errorText,"Invalid prescaler value, allowed 1 or 10",
|
||||||
|
errlen);
|
||||||
|
break;
|
||||||
|
case BADFREQ:
|
||||||
|
strncpy(errorText,"Bad timer frequency: 10 or 1000 allowed",errlen);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sprintf(pBueffel,"Unknown error code %d", self->iErrorCode);
|
||||||
|
strncpy(errorText,pBueffel,errlen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*=======================================================================*/
|
||||||
|
static int ECBFixIt(struct __COUNTER *self, int iCode){
|
||||||
|
return COTERM;
|
||||||
|
}
|
||||||
|
/*======================================================================*/
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Load the parameters 'dot' and 'divide' for a motor or an encoder.
|
||||||
|
* 'dot' specifies the placement of a punctuation mark on the display
|
||||||
|
* of f.ex a motor position. 'divide' specifies how many times the po-
|
||||||
|
* sition is to be divided by two before it is displayed.
|
||||||
|
******************************************************************************/
|
||||||
|
static void
|
||||||
|
Dot_divide (int device, int data, pECB ecb)
|
||||||
|
{
|
||||||
|
int function, dot, divide;
|
||||||
|
Z80_reg x_inreg, out;
|
||||||
|
|
||||||
|
if (data == 0) /* If zero, dont send dot/divide) */
|
||||||
|
return;
|
||||||
|
|
||||||
|
dot = 0;
|
||||||
|
while ((data%10) == 0)
|
||||||
|
{
|
||||||
|
dot++;
|
||||||
|
data /= 10;
|
||||||
|
}
|
||||||
|
divide = 0;
|
||||||
|
while ((data%2) == 0)
|
||||||
|
{
|
||||||
|
divide++;
|
||||||
|
data /= 2;
|
||||||
|
}
|
||||||
|
if (data != 1) /* If != 1, not a binary No. */
|
||||||
|
return;
|
||||||
|
if (dot > 0)
|
||||||
|
dot = 8 - dot;
|
||||||
|
x_inreg.c = 0; /* Specify input */
|
||||||
|
x_inreg.b = (unsigned char) device;
|
||||||
|
x_inreg.d = (unsigned char) dot; /* Dot position */
|
||||||
|
x_inreg.e = (unsigned char) divide; /* No. of times to divide by 2 */
|
||||||
|
|
||||||
|
ecbExecute(ecb,170,x_inreg,&out);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
static int ECBSet(struct __COUNTER *self, char *name,
|
||||||
|
int iCter, float fVal){
|
||||||
|
pECBCounter pPriv = NULL;
|
||||||
|
int iVal;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pPriv = (pECBCounter)self->pData;
|
||||||
|
assert(pPriv);
|
||||||
|
|
||||||
|
iVal = (int)rint(fVal);
|
||||||
|
|
||||||
|
if(strcmp(name,"prescaler") == 0){
|
||||||
|
if(iCter < 0 || iCter > 7){
|
||||||
|
self->iErrorCode = INVALIDCOUNTER;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
if(iVal != 1 && iVal != 10){
|
||||||
|
self->iErrorCode = INVALIDPRESCALER;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
pPriv->prescaler[iCter] = (unsigned char)iVal;
|
||||||
|
return OKOK;
|
||||||
|
} else if(strcmp(name,"tfreq") == 0){
|
||||||
|
if(fVal == 1000){
|
||||||
|
pPriv->prescaler[0] = 1;
|
||||||
|
pPriv->tfreq = 1000;
|
||||||
|
Dot_divide(64,1000,pPriv->ecb);
|
||||||
|
return OKOK;
|
||||||
|
} else if(fVal == 10){
|
||||||
|
pPriv->tfreq = 10;
|
||||||
|
pPriv->prescaler[0] = 10;
|
||||||
|
Dot_divide(64,10,pPriv->ecb);
|
||||||
|
return OKOK;
|
||||||
|
} else {
|
||||||
|
self->iErrorCode = BADFREQ;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self->iErrorCode = UNKNOWNPAR;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*===================================================================*/
|
||||||
|
static int ECBGet(struct __COUNTER *self, char *name,
|
||||||
|
int iCter, float *fVal){
|
||||||
|
pECBCounter pPriv = NULL;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pPriv = (pECBCounter)self->pData;
|
||||||
|
assert(pPriv);
|
||||||
|
|
||||||
|
if(strcmp(name,"prescaler") == 0){
|
||||||
|
*fVal = (float)pPriv->prescaler[iCter];
|
||||||
|
return OKOK;
|
||||||
|
} else if(strcmp(name,"tfreq") == 0){
|
||||||
|
*fVal = (float)pPriv->tfreq;
|
||||||
|
return OKOK;
|
||||||
|
} else{
|
||||||
|
self->iErrorCode = UNKNOWNPAR;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*=====================================================================*/
|
||||||
|
static int ECBSend(struct __COUNTER *self, char *text,
|
||||||
|
char *reply, int replylen){
|
||||||
|
strncpy(reply,"ECB does not feast on ASCII strings, refused!",
|
||||||
|
replylen);
|
||||||
|
return OKOK;
|
||||||
|
}
|
||||||
|
/*====================================================================*/
|
||||||
|
pCounterDriver MakeECBCounter(char *ecb){
|
||||||
|
pECBCounter pPriv = NULL;
|
||||||
|
pCounterDriver self = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
memory for everybody
|
||||||
|
*/
|
||||||
|
self = CreateCounterDriver("ecb","ecb");
|
||||||
|
pPriv = (pECBCounter)malloc(sizeof(ECBCounter));
|
||||||
|
if(self == NULL || pPriv == NULL){
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(pPriv,0,sizeof(ECBCounter));
|
||||||
|
|
||||||
|
/*
|
||||||
|
initialize private data structure
|
||||||
|
*/
|
||||||
|
pPriv->ecb = (pECB)FindCommandData(pServ->pSics,ecb,"ECB");
|
||||||
|
if(pPriv->ecb == NULL){
|
||||||
|
DeleteCounterDriver(self);
|
||||||
|
free(pPriv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for(i = 0; i < 8; i++){
|
||||||
|
pPriv->prescaler[i] = 1;
|
||||||
|
}
|
||||||
|
pPriv->tfreq = 1000;
|
||||||
|
pPriv->control = 1;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
assign function pointers
|
||||||
|
*/
|
||||||
|
self->GetStatus = ECBGetStatus;
|
||||||
|
self->Start = ECBStart;
|
||||||
|
self->Pause = ECBPause;
|
||||||
|
self->Continue = ECBContinue;
|
||||||
|
self->Halt = ECBHalt;
|
||||||
|
self->ReadValues = ECBTransfer;
|
||||||
|
self->GetError = ECBGetError;
|
||||||
|
self->TryAndFixIt = ECBFixIt;
|
||||||
|
self->Set = ECBSet;
|
||||||
|
self->Get = ECBGet;
|
||||||
|
self->Send = ECBSend;
|
||||||
|
self->KillPrivate = NULL;
|
||||||
|
|
||||||
|
self->pData = pPriv;
|
||||||
|
return self;
|
||||||
|
}
|
17
ecbcounter.h
Normal file
17
ecbcounter.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
Header file for the counter driver for the Risoe ECB system.
|
||||||
|
|
||||||
|
copyright: see file COPYRIGHT
|
||||||
|
|
||||||
|
Mark Koennecke, January 2003
|
||||||
|
-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef ECBCOUNTER
|
||||||
|
#define ECBCOUNTER
|
||||||
|
|
||||||
|
#include "countdriv.h"
|
||||||
|
|
||||||
|
pCounterDriver MakeECBCounter(char *ecb);
|
||||||
|
void KillECBCounter(CounterDriver *pDriv);
|
||||||
|
|
||||||
|
#endif
|
693
el737driv.c
Normal file
693
el737driv.c
Normal file
@ -0,0 +1,693 @@
|
|||||||
|
/*----------------------------------------------------------------------
|
||||||
|
This is driver for a standard PSI EL737 counter box as used at
|
||||||
|
SINQ
|
||||||
|
|
||||||
|
copyright: see file COPYRIGHT
|
||||||
|
|
||||||
|
extracted from countdriv.c. Mark Koennecke, June 2003
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <fortify.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sics.h>
|
||||||
|
#include <countdriv.h>
|
||||||
|
#include <splitter.h>
|
||||||
|
#include "hardsup/sinq_prototypes.h"
|
||||||
|
#include "hardsup/el737_def.h"
|
||||||
|
#include "hardsup/el737fix.h"
|
||||||
|
/*----------------------------- EL737 ------------------------------------*/
|
||||||
|
typedef struct {
|
||||||
|
char *host;
|
||||||
|
int iPort;
|
||||||
|
int iChannel;
|
||||||
|
void *pData;
|
||||||
|
int finishCount;
|
||||||
|
} EL737st;
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
static int EL737GetStatus(struct __COUNTER *self, float *fControl)
|
||||||
|
{
|
||||||
|
int iRet;
|
||||||
|
int iC1, iC2, iC3,iC4,iRS;
|
||||||
|
float fTime;
|
||||||
|
EL737st *pEL737;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pEL737 = (EL737st *)self->pData;
|
||||||
|
assert(pEL737);
|
||||||
|
iRet = EL737_GetStatus(&pEL737->pData,&iC1,&iC2,&iC3,&iC4,&fTime,&iRS);
|
||||||
|
if(self->eMode == eTimer)
|
||||||
|
{
|
||||||
|
*fControl = fTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*fControl = iC1;
|
||||||
|
}
|
||||||
|
/* store time */
|
||||||
|
self->fTime = fTime;
|
||||||
|
|
||||||
|
if(iRet != 1)
|
||||||
|
{
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
self->lCounts[0] = iC2;
|
||||||
|
self->lCounts[1] = iC1;
|
||||||
|
self->lCounts[2] = iC3;
|
||||||
|
self->lCounts[3] = iC4;
|
||||||
|
|
||||||
|
/* get extra counters for 8-fold counter boxes */
|
||||||
|
iRet = EL737_GetStatusExtra(&pEL737->pData,&iC1,&iC2,&iC3,&iC4);
|
||||||
|
self->lCounts[4] = iC1;
|
||||||
|
self->lCounts[5] = iC2;
|
||||||
|
self->lCounts[6] = iC3;
|
||||||
|
self->lCounts[7] = iC4;
|
||||||
|
if(iRS == 0)
|
||||||
|
{
|
||||||
|
pEL737->finishCount++;
|
||||||
|
if(pEL737->finishCount >= 2)
|
||||||
|
{
|
||||||
|
return HWIdle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return HWBusy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if((iRS == 1) || (iRS == 2))
|
||||||
|
{
|
||||||
|
pEL737->finishCount = 0;
|
||||||
|
return HWBusy;
|
||||||
|
}
|
||||||
|
else if( (iRS == 5) || (iRS == 6))
|
||||||
|
{
|
||||||
|
pEL737->finishCount = 0;
|
||||||
|
return HWNoBeam;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pEL737->finishCount = 0;
|
||||||
|
return HWPause;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef NONINTF
|
||||||
|
extern float nintf(float f);
|
||||||
|
#endif
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
static int EL737Start(struct __COUNTER *self)
|
||||||
|
{
|
||||||
|
int iRet, iRS;
|
||||||
|
EL737st *pEL737;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pEL737 = (EL737st *)self->pData;
|
||||||
|
assert(pEL737);
|
||||||
|
|
||||||
|
|
||||||
|
self->fTime = 0.;
|
||||||
|
|
||||||
|
if(self->eMode == ePreset)
|
||||||
|
{
|
||||||
|
iRet = EL737_StartCnt(&pEL737->pData,(int)nintf(self->fPreset),&iRS);
|
||||||
|
if(iRet == 1)
|
||||||
|
{
|
||||||
|
pEL737->finishCount = 0;
|
||||||
|
return OKOK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(self->eMode == eTimer)
|
||||||
|
{
|
||||||
|
iRet = EL737_StartTime(&pEL737->pData,self->fPreset,&iRS);
|
||||||
|
if(iRet == 1)
|
||||||
|
{
|
||||||
|
pEL737->finishCount = 0;
|
||||||
|
return OKOK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
static int EL737Pause(struct __COUNTER *self)
|
||||||
|
{
|
||||||
|
int iRet, iRS;
|
||||||
|
EL737st *pEL737;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pEL737 = (EL737st *)self->pData;
|
||||||
|
assert(pEL737);
|
||||||
|
|
||||||
|
|
||||||
|
iRet = EL737_Pause(&pEL737->pData,&iRS);
|
||||||
|
if(iRet == 1)
|
||||||
|
{
|
||||||
|
return OKOK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
static int EL737Continue(struct __COUNTER *self)
|
||||||
|
{
|
||||||
|
int iRet, iRS;
|
||||||
|
EL737st *pEL737;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pEL737 = (EL737st *)self->pData;
|
||||||
|
assert(pEL737);
|
||||||
|
|
||||||
|
|
||||||
|
iRet = EL737_Continue(&pEL737->pData,&iRS);
|
||||||
|
if(iRet == 1)
|
||||||
|
{
|
||||||
|
return OKOK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
static int EL737Halt(struct __COUNTER *self)
|
||||||
|
{
|
||||||
|
int iRet, iC1, iC2, iC3, iC4,iRS;
|
||||||
|
float fPreset;
|
||||||
|
EL737st *pEL737;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pEL737 = (EL737st *)self->pData;
|
||||||
|
assert(pEL737);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
iRet = EL737_Stop(&pEL737->pData,&iC1, &iC2,&iC3,&iC4,&fPreset,&iRS);
|
||||||
|
if(iRet == 1)
|
||||||
|
{
|
||||||
|
self->lCounts[0] = iC2;
|
||||||
|
self->lCounts[1] = iC1;
|
||||||
|
self->lCounts[2] = iC3;
|
||||||
|
self->lCounts[3] = iC4;
|
||||||
|
return OKOK;
|
||||||
|
}
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
static int EL737ReadValues(struct __COUNTER *self)
|
||||||
|
{
|
||||||
|
int iRet;
|
||||||
|
int iC1, iC2, iC3,iC4,iRS;
|
||||||
|
float fTime;
|
||||||
|
EL737st *pEL737;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pEL737 = (EL737st *)self->pData;
|
||||||
|
assert(pEL737);
|
||||||
|
|
||||||
|
|
||||||
|
iRet = EL737_GetStatus(&pEL737->pData,&iC1,&iC2,&iC3,&iC4,&fTime,&iRS);
|
||||||
|
if(iRet != 1)
|
||||||
|
{
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
self->fTime = fTime;
|
||||||
|
|
||||||
|
self->lCounts[0] = iC2;
|
||||||
|
self->lCounts[1] = iC1;
|
||||||
|
self->lCounts[2] = iC3;
|
||||||
|
self->lCounts[3] = iC4;
|
||||||
|
/* get extra counters for 8-fold counter boxes */
|
||||||
|
iRet = EL737_GetStatusExtra(&pEL737->pData,&iC1,&iC2,&iC3,&iC4);
|
||||||
|
self->lCounts[4] = iC1;
|
||||||
|
self->lCounts[5] = iC2;
|
||||||
|
self->lCounts[6] = iC3;
|
||||||
|
self->lCounts[7] = iC4;
|
||||||
|
|
||||||
|
return OKOK;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
EL737Error2Text converts between an EL734 error code to text
|
||||||
|
-----------------------------------------------------------------------------*/
|
||||||
|
static void EL737Error2Text(char *pBuffer, int iErr)
|
||||||
|
{
|
||||||
|
switch(iErr)
|
||||||
|
{
|
||||||
|
case EL737__BAD_ADR:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_ADR");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_OVFL:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_OVFL");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_BSY:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_BSY");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_SNTX:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_SNTX");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_CONNECT:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_CONNECT");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_FLUSH:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_FLUSH");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_DEV:
|
||||||
|
strcpy(pBuffer,"EL734__BAD_DEV");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_ID:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_ID");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_ILLG:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_ILLG");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_LOC:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_LOC");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_MALLOC:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_MALLOC");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_NOT_BCD:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_NOT_BCD");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_OFL:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_OFL");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_PAR:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_PAR");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EL737__BAD_RECV:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_RECV");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_RECV_NET:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_RECV_NET");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_RECV_PIPE:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_RECV_PIPE");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_RECV_UNKN:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_RECV_UNKN");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_RECVLEN:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_RECVLEN");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_RECV1:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_RECV1");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_RECV1_NET:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_RECV1_NET");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_RECV1_PIPE:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_RECV1_PIPE");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_RNG:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_RNG");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_SEND:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_SEND");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_SEND_PIPE:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_SEND_PIPE");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_SEND_NET:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_SEND_NET");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_SEND_UNKN:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_SEND_UNKN");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_SENDLEN:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_SENDLEN");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_SOCKET:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_SOCKET");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_TMO:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_TMO");
|
||||||
|
break;
|
||||||
|
case EL737__FORCED_CLOSED:
|
||||||
|
strcpy(pBuffer,"EL737__FORCED_CLOSED");
|
||||||
|
break;
|
||||||
|
case EL737__BAD_ASYNSRV:
|
||||||
|
strcpy(pBuffer,"EL737__BAD_ASYNSRV");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sprintf(pBuffer,"Unknown EL737 error %d", iErr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
static int EL737GetError(struct __COUNTER *self, int *iCode,
|
||||||
|
char *error, int iErrLen)
|
||||||
|
{
|
||||||
|
char *pErr = NULL;
|
||||||
|
int iC1, iC2, iC3;
|
||||||
|
char pBueffel[256];
|
||||||
|
|
||||||
|
if(self->iErrorCode == UNKNOWNPAR)
|
||||||
|
{
|
||||||
|
strncpy(error,"unknown internal parameter code",iErrLen);
|
||||||
|
*iCode = self->iErrorCode;
|
||||||
|
self->iErrorCode = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if(self->iErrorCode == BADCOUNTER)
|
||||||
|
{
|
||||||
|
strncpy(error,"monitor cannot be selected",iErrLen);
|
||||||
|
*iCode = self->iErrorCode;
|
||||||
|
self->iErrorCode = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EL737_ErrInfo(&pErr,&iC1,&iC2, &iC3);
|
||||||
|
EL737Error2Text(pBueffel,iC1);
|
||||||
|
|
||||||
|
strncpy(error,pBueffel,iErrLen);
|
||||||
|
*iCode = iC1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
static int EL737TryAndFixIt(struct __COUNTER *self, int iCode)
|
||||||
|
{
|
||||||
|
EL737st *pEL737;
|
||||||
|
int iRet;
|
||||||
|
char pCommand[50], pReply[50];
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pEL737 = (EL737st *)self->pData;
|
||||||
|
assert(pEL737);
|
||||||
|
|
||||||
|
switch(iCode)
|
||||||
|
{
|
||||||
|
case EL737__BAD_ILLG:
|
||||||
|
case EL737__BAD_ADR:
|
||||||
|
case EL737__BAD_PAR:
|
||||||
|
case EL737__BAD_TMO:
|
||||||
|
case EL737__BAD_REPLY:
|
||||||
|
case EL737__BAD_SNTX:
|
||||||
|
case EL737__BAD_OVFL:
|
||||||
|
return COREDO;
|
||||||
|
break;
|
||||||
|
case EL737__BAD_BSY:
|
||||||
|
strcpy(pCommand,"S \r");
|
||||||
|
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
|
||||||
|
if(iRet < 0)
|
||||||
|
{
|
||||||
|
return COTERM;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return COREDO;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EL737__BAD_LOC:
|
||||||
|
strcpy(pCommand,"rmt 1\r");
|
||||||
|
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
|
||||||
|
if(iRet < 0)
|
||||||
|
{
|
||||||
|
return COTERM;
|
||||||
|
}
|
||||||
|
strcpy(pCommand,"echo 2\r");
|
||||||
|
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
|
||||||
|
if(iRet < 0)
|
||||||
|
{
|
||||||
|
return COTERM;
|
||||||
|
}
|
||||||
|
strcpy(pCommand,"ra\r");
|
||||||
|
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49);
|
||||||
|
if(iRet < 0)
|
||||||
|
{
|
||||||
|
return COTERM;
|
||||||
|
}
|
||||||
|
return COREDO;
|
||||||
|
break;
|
||||||
|
case EL737__BAD_DEV:
|
||||||
|
case EL737__BAD_ID:
|
||||||
|
case EL737__BAD_NOT_BCD:
|
||||||
|
case UNKNOWNPAR:
|
||||||
|
case BADCOUNTER:
|
||||||
|
return COTERM;
|
||||||
|
break;
|
||||||
|
case EL737__FORCED_CLOSED:
|
||||||
|
iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort,
|
||||||
|
pEL737->iChannel);
|
||||||
|
if(iRet == 1)
|
||||||
|
{
|
||||||
|
return COREDO;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return COTERM;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EL737__BAD_OFL:
|
||||||
|
EL737_Close(&pEL737->pData,0);
|
||||||
|
iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort,
|
||||||
|
pEL737->iChannel);
|
||||||
|
if(iRet == 1)
|
||||||
|
{
|
||||||
|
return COREDO;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return COTERM;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
/* case EL737__BAD_ASYNSRV:
|
||||||
|
EL737_Close(&pEL737->pData,1);
|
||||||
|
return COREDO;
|
||||||
|
*/ default:
|
||||||
|
/* try to reopen connection */
|
||||||
|
|
||||||
|
EL737_Close(&pEL737->pData,1);
|
||||||
|
iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort,
|
||||||
|
pEL737->iChannel);
|
||||||
|
if(iRet == 1)
|
||||||
|
{
|
||||||
|
return COREDO;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return COTERM;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return COTERM;
|
||||||
|
}
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
static int EL737Set(struct __COUNTER *self, char *name, int iCter,
|
||||||
|
float fVal)
|
||||||
|
{
|
||||||
|
int iRet;
|
||||||
|
EL737st *pEL737;
|
||||||
|
char pCommand[80],pReply[80];
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pEL737 = (EL737st *)self->pData;
|
||||||
|
assert(pEL737);
|
||||||
|
|
||||||
|
if(strcmp(name,"threshold") == 0)
|
||||||
|
{
|
||||||
|
sprintf(pCommand,"DL %1.1d %f\r",iCter,fVal);
|
||||||
|
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79);
|
||||||
|
if(iRet == 1)
|
||||||
|
{
|
||||||
|
if(pCommand[0] == '?')
|
||||||
|
{
|
||||||
|
self->iErrorCode = BADCOUNTER;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
sprintf(pCommand,"DR %1.1d \r",iCter);
|
||||||
|
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79);
|
||||||
|
if(iRet == 1)
|
||||||
|
{
|
||||||
|
if(pCommand[0] == '?')
|
||||||
|
{
|
||||||
|
self->iErrorCode = BADCOUNTER;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
return OKOK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self->iErrorCode = UNKNOWNPAR;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
static int EL737Get(struct __COUNTER *self, char *name, int iCter,
|
||||||
|
float *fVal)
|
||||||
|
{
|
||||||
|
int iRet;
|
||||||
|
EL737st *pEL737;
|
||||||
|
char pCommand[80],pReply[80];
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pEL737 = (EL737st *)self->pData;
|
||||||
|
assert(pEL737);
|
||||||
|
|
||||||
|
if(strcmp(name,"threshold") == 0)
|
||||||
|
{
|
||||||
|
sprintf(pCommand,"DL %1.1d\r",iCter);
|
||||||
|
iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79);
|
||||||
|
if(iRet == 1)
|
||||||
|
{
|
||||||
|
if(pReply[0] == '?')
|
||||||
|
{
|
||||||
|
self->iErrorCode = BADCOUNTER;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
sscanf(pReply,"%f",fVal);
|
||||||
|
return OKOK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self->iErrorCode = UNKNOWNPAR;
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
static int EL737Send(struct __COUNTER *self, char *pText, char *pReply,
|
||||||
|
int iReplyLen)
|
||||||
|
{
|
||||||
|
EL737st *pEL737;
|
||||||
|
char pBuffer[256];
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pEL737 = (EL737st *)self->pData;
|
||||||
|
assert(pEL737);
|
||||||
|
|
||||||
|
/* ensure a \r at the end of the text */
|
||||||
|
if(strlen(pText) > 254)
|
||||||
|
{
|
||||||
|
strncpy(pReply,"Command to long",iReplyLen);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
strcpy(pBuffer,pText);
|
||||||
|
if(strchr(pBuffer,(int)'\r') == NULL)
|
||||||
|
{
|
||||||
|
strcat(pBuffer,"\r");
|
||||||
|
}
|
||||||
|
|
||||||
|
return EL737_SendCmnd(&pEL737->pData,pBuffer,pReply,iReplyLen);
|
||||||
|
}
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
pCounterDriver CreateEL737Counter(SConnection *pCon, char *name,
|
||||||
|
int argc, char *argv[]){
|
||||||
|
char *pHost;
|
||||||
|
int iPort, iChannel;
|
||||||
|
|
||||||
|
if(argc < 3){
|
||||||
|
SCWrite(pCon,
|
||||||
|
"ERROR: insuficient number of arguments to create EL737 counter",
|
||||||
|
eError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(!isNumeric(argv[1]) || !isNumeric(argv[2])){
|
||||||
|
SCWrite(pCon,"ERROR: expected numeric arguments for port and channel",
|
||||||
|
eError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
iPort = atoi(argv[1]);
|
||||||
|
iChannel = atoi(argv[2]);
|
||||||
|
return NewEL737Counter(name,argv[0],iPort,iChannel);
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
pCounterDriver NewEL737Counter(char *name, char *host, int iPort, int iChannel)
|
||||||
|
{
|
||||||
|
pCounterDriver pRes = NULL;
|
||||||
|
EL737st *pData = NULL;
|
||||||
|
int iRet;
|
||||||
|
int iC1, iC2, iC3;
|
||||||
|
char *pErr;
|
||||||
|
char pBueffel[132];
|
||||||
|
|
||||||
|
pRes = CreateCounterDriver(name, "EL737");
|
||||||
|
if(!pRes)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open connection to counter */
|
||||||
|
pData = (EL737st *)malloc(sizeof(EL737st));
|
||||||
|
if(!pData)
|
||||||
|
{
|
||||||
|
DeleteCounterDriver(pRes);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
pData->host = strdup(host);
|
||||||
|
pData->iPort = iPort;
|
||||||
|
pData->iChannel = iChannel;
|
||||||
|
pData->pData = NULL;
|
||||||
|
iRet = EL737_Open(&(pData->pData), host,iPort,iChannel);
|
||||||
|
if(iRet != 1)
|
||||||
|
{
|
||||||
|
EL737_ErrInfo(&pErr,&iC1,&iC2, &iC3);
|
||||||
|
DeleteCounterDriver(pRes);
|
||||||
|
if(pData->host)
|
||||||
|
{
|
||||||
|
free(pData->host);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
pRes->pData = (void *)pData;
|
||||||
|
|
||||||
|
/* assign functions */
|
||||||
|
pRes->GetStatus = EL737GetStatus;
|
||||||
|
pRes->Start = EL737Start;
|
||||||
|
pRes->Halt = EL737Halt;
|
||||||
|
pRes->ReadValues = EL737ReadValues;
|
||||||
|
pRes->GetError = EL737GetError;
|
||||||
|
pRes->TryAndFixIt = EL737TryAndFixIt;
|
||||||
|
pRes->Pause = EL737Pause;
|
||||||
|
pRes->Continue = EL737Continue;
|
||||||
|
pRes->Set = EL737Set;
|
||||||
|
pRes->Get = EL737Get;
|
||||||
|
pRes->Send = EL737Send;
|
||||||
|
pRes->KillPrivate = KillEL737Counter;
|
||||||
|
pRes->iNoOfMonitors = 7;
|
||||||
|
pRes->fTime = 0.;
|
||||||
|
|
||||||
|
return pRes;
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
void KillEL737Counter(pCounterDriver self)
|
||||||
|
{
|
||||||
|
EL737st *pEL737 = NULL;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pEL737 = (EL737st *)self->pData;
|
||||||
|
assert(pEL737);
|
||||||
|
|
||||||
|
EL737_Close(&pEL737->pData,0);
|
||||||
|
if(pEL737->host)
|
||||||
|
{
|
||||||
|
free(pEL737->host);
|
||||||
|
}
|
||||||
|
}
|
395
eurodriv.c
Normal file
395
eurodriv.c
Normal file
@ -0,0 +1,395 @@
|
|||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
E U R O D R I V
|
||||||
|
|
||||||
|
This file contains the implementation for the Eurotherm temperature
|
||||||
|
controller as used at SANS. The Eurotherm is a grossly strange device
|
||||||
|
which has a very weird command protocoll. The implementation here uses
|
||||||
|
the EI-Bisynch Protocoll option. This has to be configured in the
|
||||||
|
Eurotherm on the manual interface!! Also watch out for the unusual RS232-
|
||||||
|
setting: 7 bits, even parity, 1 stop bit.
|
||||||
|
|
||||||
|
Mark Koennecke, May 1999
|
||||||
|
|
||||||
|
Copyright: see copyright.h
|
||||||
|
----------------------------------------------------------------------------*/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <fortify.h>
|
||||||
|
#include <conman.h>
|
||||||
|
#include <servlog.h>
|
||||||
|
#include <fortify.h>
|
||||||
|
|
||||||
|
typedef struct __EVDriver *pEVDriver;
|
||||||
|
|
||||||
|
#include <evdriver.i>
|
||||||
|
#include "hardsup/el734_def.h"
|
||||||
|
#include "hardsup/el734fix.h"
|
||||||
|
#include "hardsup/serialsinq.h"
|
||||||
|
#include "eurodriv.h"
|
||||||
|
|
||||||
|
#define INVALIDANSWER -1005
|
||||||
|
#define INVALIDNUMBER -1006
|
||||||
|
#define ERRNAK -1007
|
||||||
|
#define NOSEND -1008
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
typedef struct {
|
||||||
|
void *pData;
|
||||||
|
char *pHost;
|
||||||
|
int iPort;
|
||||||
|
int iChannel;
|
||||||
|
int iLastError;
|
||||||
|
} EuroDriv, *pEuroDriv;
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
int EuroGetParameter(void **pData, char *pPar,int iLen, float *fVal)
|
||||||
|
{
|
||||||
|
char pCommand[20];
|
||||||
|
char pReply[20];
|
||||||
|
char *pStart = NULL, *pEnd = NULL;
|
||||||
|
int iRet,i;
|
||||||
|
|
||||||
|
/* configure the serial port */
|
||||||
|
SerialATerm(pData,"1\x3"); /* ETX */
|
||||||
|
pCommand[0] = '\x4'; /* EOT */
|
||||||
|
pCommand[1] = '0'; /* GID*/
|
||||||
|
pCommand[2] = '0'; /* GID*/
|
||||||
|
pCommand[3] = '1'; /* UID*/
|
||||||
|
pCommand[4] = '1'; /* UID*/
|
||||||
|
pCommand[5] = '1'; /* CHAN */
|
||||||
|
for(i = 0; i < iLen; i++)
|
||||||
|
{
|
||||||
|
pCommand[6+i] = pPar[i];
|
||||||
|
}
|
||||||
|
pCommand[6+iLen] = '\x5'; /* ENQ*/
|
||||||
|
pCommand[7+iLen] = '\0';
|
||||||
|
|
||||||
|
/* send */
|
||||||
|
iRet = SerialWriteRead(pData,pCommand,pReply,19);
|
||||||
|
if(iRet != 1)
|
||||||
|
{
|
||||||
|
return iRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decode reply */
|
||||||
|
pStart = strstr(pReply,pPar);
|
||||||
|
if(!pStart)
|
||||||
|
{
|
||||||
|
if(strstr(pReply,"?TMO"))
|
||||||
|
{
|
||||||
|
return EL734__BAD_TMO;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return INVALIDANSWER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iRet = sscanf(pStart+strlen(pPar),"%f",fVal);
|
||||||
|
if(iRet != 1)
|
||||||
|
{
|
||||||
|
return INVALIDNUMBER;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
int EuroSetParameter(void **pData, char *pPar,int iLen,
|
||||||
|
char *pFormat, float fVal)
|
||||||
|
{
|
||||||
|
char pCommand[30];
|
||||||
|
char pNum[10];
|
||||||
|
char *pPtr, *pPtr2;
|
||||||
|
char pReply[20];
|
||||||
|
char bcc;
|
||||||
|
int iRet,i;
|
||||||
|
|
||||||
|
|
||||||
|
/* configure the serial port */
|
||||||
|
SerialATerm(pData,"1\x06\x15"); /* ACK,NAK */
|
||||||
|
pCommand[0] = '\x04'; /* EOT */
|
||||||
|
pCommand[1] = '0'; /* GID*/
|
||||||
|
pCommand[2] = '0'; /* GID*/
|
||||||
|
pCommand[3] = '1'; /* UID*/
|
||||||
|
pCommand[4] = '1'; /* UID*/
|
||||||
|
pCommand[5] = '\x02';
|
||||||
|
pCommand[6] = '1'; /* CHAN */
|
||||||
|
for(i = 0; i < iLen; i++)
|
||||||
|
{
|
||||||
|
pCommand[7+i] = pPar[i];
|
||||||
|
}
|
||||||
|
pPtr = pCommand + 7 + iLen;
|
||||||
|
sprintf(pNum,pFormat,fVal);
|
||||||
|
strcpy(pPtr,pNum);
|
||||||
|
pPtr += strlen(pNum);
|
||||||
|
*pPtr = '\x03';
|
||||||
|
pPtr++;
|
||||||
|
|
||||||
|
/* build the checksum */
|
||||||
|
bcc = pCommand[6];
|
||||||
|
pPtr2 = &pCommand[7];
|
||||||
|
while(pPtr2 != pPtr)
|
||||||
|
{
|
||||||
|
bcc = bcc ^ *pPtr2;
|
||||||
|
pPtr2++;
|
||||||
|
}
|
||||||
|
*pPtr = bcc;
|
||||||
|
pPtr++;
|
||||||
|
*pPtr = '\0';
|
||||||
|
|
||||||
|
/* send */
|
||||||
|
iRet = SerialSend(pData,pCommand);
|
||||||
|
if(iRet != 1)
|
||||||
|
{
|
||||||
|
return iRet;
|
||||||
|
}
|
||||||
|
iRet = SerialReceiveWithTerm(pData,pReply,19,&bcc);
|
||||||
|
/*
|
||||||
|
printf("%s\n",pReply);
|
||||||
|
*/
|
||||||
|
if(iRet != 1)
|
||||||
|
{
|
||||||
|
return iRet;
|
||||||
|
}
|
||||||
|
if(bcc == '\x15')
|
||||||
|
{
|
||||||
|
return ERRNAK;
|
||||||
|
}
|
||||||
|
if(strstr(pReply,"?TMO"))
|
||||||
|
{
|
||||||
|
return EL734__BAD_TMO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int GetEuroPos(pEVDriver self, float *fPos)
|
||||||
|
{
|
||||||
|
pEuroDriv pMe = NULL;
|
||||||
|
int iRet;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pMe = (pEuroDriv)self->pPrivate;
|
||||||
|
assert(pMe);
|
||||||
|
|
||||||
|
iRet = EuroGetParameter(&(pMe->pData),"PV",2,fPos);
|
||||||
|
if(iRet != 1)
|
||||||
|
{
|
||||||
|
pMe->iLastError = iRet;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
static int EuroRun(pEVDriver self, float fVal)
|
||||||
|
{
|
||||||
|
pEuroDriv pMe = NULL;
|
||||||
|
int iRet;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pMe = (pEuroDriv )self->pPrivate;
|
||||||
|
assert(pMe);
|
||||||
|
|
||||||
|
iRet = EuroSetParameter(&(pMe->pData),"SL",2,"%4.1f",fVal);
|
||||||
|
if(iRet != 1)
|
||||||
|
{
|
||||||
|
pMe->iLastError = iRet;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
static int EuroError(pEVDriver self, int *iCode, char *error, int iErrLen)
|
||||||
|
{
|
||||||
|
pEuroDriv pMe = NULL;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pMe = (pEuroDriv)self->pPrivate;
|
||||||
|
assert(pMe);
|
||||||
|
|
||||||
|
*iCode = pMe->iLastError;
|
||||||
|
switch(pMe->iLastError)
|
||||||
|
{
|
||||||
|
case INVALIDANSWER:
|
||||||
|
strncpy(error,"Unexpected reply from Eurotherm",iErrLen);
|
||||||
|
break;
|
||||||
|
case INVALIDNUMBER:
|
||||||
|
strncpy(error,"No number in Eurotherm answer",iErrLen);
|
||||||
|
break;
|
||||||
|
case ERRNAK:
|
||||||
|
strncpy(error,"Eurothem did NOT acknowledge command",iErrLen);
|
||||||
|
break;
|
||||||
|
case NOSEND:
|
||||||
|
strncpy(error,
|
||||||
|
"Eurotherm has a bizarre protocoll, sending things is very STUPID",iErrLen);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SerialError(pMe->iLastError,error,iErrLen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
static int EuroSend(pEVDriver self, char *pCommand, char *pReply, int iLen)
|
||||||
|
{
|
||||||
|
pEuroDriv pMe = NULL;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pMe = (pEuroDriv)self->pPrivate;
|
||||||
|
assert(pMe);
|
||||||
|
|
||||||
|
pMe->iLastError = NOSEND;
|
||||||
|
strncpy(pReply,"ERROR: Eurotherm does not support send functionality",
|
||||||
|
iLen);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
static int EuroInit(pEVDriver self)
|
||||||
|
{
|
||||||
|
pEuroDriv pMe = NULL;
|
||||||
|
int iRet;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pMe = (pEuroDriv )self->pPrivate;
|
||||||
|
assert(pMe);
|
||||||
|
|
||||||
|
pMe->pData = NULL;
|
||||||
|
iRet = SerialOpen(&pMe->pData, pMe->pHost, pMe->iPort, pMe->iChannel);
|
||||||
|
if(iRet != 1)
|
||||||
|
{
|
||||||
|
pMe->iLastError = iRet;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SerialSendTerm(&pMe->pData,"");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
static int EuroClose(pEVDriver self)
|
||||||
|
{
|
||||||
|
pEuroDriv pMe = NULL;
|
||||||
|
int iRet;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pMe = (pEuroDriv )self->pPrivate;
|
||||||
|
assert(pMe);
|
||||||
|
|
||||||
|
SerialClose(&pMe->pData);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int EuroFix(pEVDriver self, int iError)
|
||||||
|
{
|
||||||
|
pEuroDriv pMe = NULL;
|
||||||
|
int iRet;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
pMe = (pEuroDriv )self->pPrivate;
|
||||||
|
assert(pMe);
|
||||||
|
|
||||||
|
switch(iError)
|
||||||
|
{
|
||||||
|
/* network errors */
|
||||||
|
case EL734__BAD_FLUSH:
|
||||||
|
case EL734__BAD_RECV:
|
||||||
|
case EL734__BAD_RECV_NET:
|
||||||
|
case EL734__BAD_RECV_UNKN:
|
||||||
|
case EL734__BAD_RECVLEN:
|
||||||
|
case EL734__BAD_RECV1:
|
||||||
|
case EL734__BAD_RECV1_PIPE:
|
||||||
|
case EL734__BAD_RNG:
|
||||||
|
case EL734__BAD_SEND:
|
||||||
|
case EL734__BAD_SEND_PIPE:
|
||||||
|
case EL734__BAD_SEND_NET:
|
||||||
|
case EL734__BAD_SEND_UNKN:
|
||||||
|
case EL734__BAD_SENDLEN:
|
||||||
|
EuroClose(self);
|
||||||
|
iRet = EuroInit(self);
|
||||||
|
if(iRet)
|
||||||
|
{
|
||||||
|
return DEVREDO;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return DEVFAULT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
/* handable protocoll errors */
|
||||||
|
case EL734__BAD_TMO:
|
||||||
|
return DEVREDO;
|
||||||
|
break;
|
||||||
|
case ERRNAK:
|
||||||
|
case NOSEND:
|
||||||
|
case INVALIDANSWER:
|
||||||
|
case INVALIDNUMBER:
|
||||||
|
return DEVFAULT;
|
||||||
|
default:
|
||||||
|
return DEVFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return DEVFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
static int EuroHalt(pEVDriver *self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
void KillEuro(void *pData)
|
||||||
|
{
|
||||||
|
pEuroDriv pMe = NULL;
|
||||||
|
|
||||||
|
pMe = (pEuroDriv)pData;
|
||||||
|
assert(pMe);
|
||||||
|
|
||||||
|
if(pMe->pHost)
|
||||||
|
{
|
||||||
|
free(pMe->pHost);
|
||||||
|
}
|
||||||
|
free(pMe);
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
pEVDriver CreateEURODriv(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
pEVDriver pNew = NULL;
|
||||||
|
pEuroDriv pSim = NULL;
|
||||||
|
|
||||||
|
/* check for arguments */
|
||||||
|
if(argc < 3)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNew = CreateEVDriver(argc,argv);
|
||||||
|
pSim = (pEuroDriv)malloc(sizeof(EuroDriv));
|
||||||
|
memset(pSim,0,sizeof(EuroDriv));
|
||||||
|
if(!pNew || !pSim)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
pNew->pPrivate = pSim;
|
||||||
|
pNew->KillPrivate = KillEuro;
|
||||||
|
|
||||||
|
/* initalise pDILLUDriver */
|
||||||
|
pSim->iLastError = 0;
|
||||||
|
pSim->pHost = strdup(argv[0]);
|
||||||
|
pSim->iPort = atoi(argv[1]);
|
||||||
|
pSim->iChannel = atoi(argv[2]);
|
||||||
|
|
||||||
|
/* initialise function pointers */
|
||||||
|
pNew->SetValue = EuroRun;
|
||||||
|
pNew->GetValue = GetEuroPos;
|
||||||
|
pNew->Send = EuroSend;
|
||||||
|
pNew->GetError = EuroError;
|
||||||
|
pNew->TryFixIt = EuroFix;
|
||||||
|
pNew->Init = EuroInit;
|
||||||
|
pNew->Close = EuroClose;
|
||||||
|
|
||||||
|
return pNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
23
eurodriv.h
Normal file
23
eurodriv.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*------------------------------------------------------------------------
|
||||||
|
E U R O D R I V
|
||||||
|
|
||||||
|
A environment control driver for the SANS Eurotherm temperature
|
||||||
|
controller.
|
||||||
|
|
||||||
|
Mark Koennecke, May 1999
|
||||||
|
|
||||||
|
copyright: see copyright.h
|
||||||
|
---------------------------------------------------------------------------*/
|
||||||
|
#ifndef EURODRIV
|
||||||
|
#define EURODRIV
|
||||||
|
pEVDriver CreateEURODriv(int argc, char *argv[]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
these are hooks to implement further functionality which,
|
||||||
|
I'am sure, Joachim Kohlbrecher will request.
|
||||||
|
*/
|
||||||
|
int EuroGetParameter(void **pData, char *pPar, int iLen, float *fVal);
|
||||||
|
int EuroSetParameter(void **pData, char *pPar, int iLen,
|
||||||
|
char *pFormat, float fVal);
|
||||||
|
|
||||||
|
#endif
|
242
frame.c
Normal file
242
frame.c
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
A module implementing functionality for reading single time frames
|
||||||
|
from PSD time-of-flight datasets. This can be done either from
|
||||||
|
SINQHM histogram memories or from old data files visible from the
|
||||||
|
SICS server. The result is sent to the demanding client in UUencoded
|
||||||
|
format.
|
||||||
|
|
||||||
|
copyright: see file COPYRIGHT
|
||||||
|
|
||||||
|
Mark Koennecke, February-March 2003
|
||||||
|
---------------------------------------------------------------------------*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "fortify.h"
|
||||||
|
#include "sics.h"
|
||||||
|
#include "stringdict.h"
|
||||||
|
#include "counter.h"
|
||||||
|
#include "HistMem.h"
|
||||||
|
#include "HistMem.i"
|
||||||
|
#include "HistDriv.i"
|
||||||
|
#include "hardsup/sinqhm.h"
|
||||||
|
#include "sinqhmdriv.i"
|
||||||
|
#include "nxdict.h"
|
||||||
|
#include "frame.h"
|
||||||
|
/*======================================================================*/
|
||||||
|
static int readHMFrame(SConnection *pCon, pHistMem pHM, int nFrame){
|
||||||
|
HistInt *buffer = NULL;
|
||||||
|
int iDim[MAXDIM], rank, length, status, i, noTimeBins;
|
||||||
|
pSINQHM pHist;
|
||||||
|
SinqHMDriv *pTata;
|
||||||
|
const float *timeBin;
|
||||||
|
|
||||||
|
/*
|
||||||
|
find dimensions and allocate data
|
||||||
|
*/
|
||||||
|
GetHistDim(pHM,iDim,&rank);
|
||||||
|
timeBin = GetHistTimeBin(pHM,&noTimeBins);
|
||||||
|
|
||||||
|
if(rank < 2){
|
||||||
|
SCWrite(pCon,"ERROR: no PSD data present, cannot send frame",eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
length = iDim[0]*iDim[1];
|
||||||
|
buffer = (HistInt *)malloc((length + 2)*sizeof(HistInt));
|
||||||
|
if(!buffer){
|
||||||
|
SCWrite(pCon,"ERROR: out of memory in readHMFrame",eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memset(buffer,0,(length+2)*sizeof(HistInt));
|
||||||
|
|
||||||
|
/*
|
||||||
|
first two values are dimensions
|
||||||
|
*/
|
||||||
|
buffer[0] = htonl(iDim[0]);
|
||||||
|
buffer[1] = htonl(iDim[1]);
|
||||||
|
|
||||||
|
if(isSINQHMDriv(pHM->pDriv) && noTimeBins > 2) {
|
||||||
|
/*
|
||||||
|
read from HM. The 5 is PROJECT__FRAME in Sinqhm_def.h
|
||||||
|
Again: be friendly: fix out of range frames
|
||||||
|
*/
|
||||||
|
if(nFrame < 0){
|
||||||
|
nFrame = 0;
|
||||||
|
}
|
||||||
|
if(nFrame >= noTimeBins){
|
||||||
|
nFrame = noTimeBins-1;
|
||||||
|
}
|
||||||
|
pTata = (SinqHMDriv *)pHM->pDriv->pPriv;
|
||||||
|
pHist = (pSINQHM)pTata->pMaster;
|
||||||
|
status = SINQHMProject(pHist, 0x0005, 0, nFrame,
|
||||||
|
0, iDim[1], buffer+2,length*sizeof(HistInt));
|
||||||
|
if(status != 1){
|
||||||
|
SCWrite(pCon,"ERROR: SINQHM refused to deliver frame",eError);
|
||||||
|
free(buffer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
be friendly, just read the 2D data which is there
|
||||||
|
*/
|
||||||
|
status = GetHistogram(pHM,pCon,0,0,length,buffer+2,length*sizeof(HistInt));
|
||||||
|
if(!status){
|
||||||
|
free(buffer);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
enforce network byte order
|
||||||
|
*/
|
||||||
|
for(i = 0; i < length; i++){
|
||||||
|
buffer[i+2] = htonl(buffer[i+2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCWriteUUencoded(pCon,"framedata", buffer,(length+2)*sizeof(HistInt));
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*=======================================================================*/
|
||||||
|
static int readFileFrame(SConnection *pCon,
|
||||||
|
char *file, char *dictFile,
|
||||||
|
char *alias, int nFrame){
|
||||||
|
int status, iDim[NX_MAXRANK], rank = 0, type = 0;
|
||||||
|
int iStart[3], iSize[3], length, i;
|
||||||
|
int *buffer = NULL;
|
||||||
|
NXhandle fileHandle;
|
||||||
|
NXdict dictHandle;
|
||||||
|
char error[512];
|
||||||
|
|
||||||
|
status = NXopen(file,NXACC_READ,&fileHandle);
|
||||||
|
if(status != NX_OK){
|
||||||
|
sprintf(error,"ERROR: failed to open %s", file);
|
||||||
|
SCWrite(pCon,error,eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
status = NXDinitfromfile(dictFile, &dictHandle);
|
||||||
|
if(status != NX_OK){
|
||||||
|
sprintf(error,"ERROR: failed to open dictionary %s", dictFile);
|
||||||
|
NXclose(&fileHandle);
|
||||||
|
SCWrite(pCon,error,eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = NXDopenalias(fileHandle,dictHandle,alias);
|
||||||
|
if(status != NX_OK){
|
||||||
|
sprintf(error,"ERROR: failed to open alias %s", alias);
|
||||||
|
NXclose(&fileHandle);
|
||||||
|
NXDclose(dictHandle,NULL);
|
||||||
|
SCWrite(pCon,error,eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = NXgetinfo(fileHandle,&rank,iDim,&type);
|
||||||
|
if(type != NX_INT32 && type != NX_UINT32)type = -1;
|
||||||
|
if(status != NX_OK || rank < 2 || type < 0 ){
|
||||||
|
sprintf(error,"ERROR: Dataset does not match!");
|
||||||
|
NXclose(&fileHandle);
|
||||||
|
NXDclose(dictHandle,NULL);
|
||||||
|
SCWrite(pCon,error,eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
allocate space
|
||||||
|
*/
|
||||||
|
length = iDim[0]*iDim[1];
|
||||||
|
buffer = (int *)malloc((length+2)*sizeof(int));
|
||||||
|
if(!buffer){
|
||||||
|
NXclose(&fileHandle);
|
||||||
|
NXDclose(dictHandle,NULL);
|
||||||
|
SCWrite(pCon,"ERROR: out of memory in readFrameFromFile",eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memset(buffer,0,(length+2)*sizeof(int));
|
||||||
|
|
||||||
|
/*
|
||||||
|
first two values: dimensions
|
||||||
|
*/
|
||||||
|
buffer[0] = htonl(iDim[0]);
|
||||||
|
buffer[1] = htonl(iDim[1]);
|
||||||
|
|
||||||
|
if(rank == 2){
|
||||||
|
/*
|
||||||
|
be friendly
|
||||||
|
*/
|
||||||
|
status = NXgetdata(fileHandle,buffer+2);
|
||||||
|
} else {
|
||||||
|
iStart[0] = iStart[1] = 0;
|
||||||
|
iStart[2] = nFrame;
|
||||||
|
iSize[0] = iDim[0];
|
||||||
|
iSize[1] = iDim[1];
|
||||||
|
iSize[2] = 1;
|
||||||
|
status = NXgetslab(fileHandle,buffer+2,iStart,iSize);
|
||||||
|
}
|
||||||
|
if(status != NX_OK){
|
||||||
|
NXclose(&fileHandle);
|
||||||
|
NXDclose(dictHandle,NULL);
|
||||||
|
free(buffer);
|
||||||
|
SCWrite(pCon,"ERROR: failed to read data",eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
enforce network byte order
|
||||||
|
*/
|
||||||
|
for(i = 0; i < length; i++){
|
||||||
|
buffer[2+i] = htonl(buffer[2+i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCWriteUUencoded(pCon,"framedata",buffer,(length+2)*sizeof(int));
|
||||||
|
NXclose(&fileHandle);
|
||||||
|
NXDclose(dictHandle,NULL);
|
||||||
|
free(buffer);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*=======================================================================*/
|
||||||
|
int PSDFrameAction(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||||
|
int argc, char *argv[]){
|
||||||
|
pHistMem pHM;
|
||||||
|
int nFrame;
|
||||||
|
|
||||||
|
if(argc < 2){
|
||||||
|
SCWrite(pCon,"ERROR: Insufficient number of arguments to PSDFrame",
|
||||||
|
eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
strtolower(argv[1]);
|
||||||
|
if(strcmp(argv[1],"hm") == 0){
|
||||||
|
if(argc < 4){
|
||||||
|
SCWrite(pCon,"ERROR: Insufficient number of arguments to PSDFrame",
|
||||||
|
eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pHM = (pHistMem)FindCommandData(pSics,argv[2],"HistMem");
|
||||||
|
if(pHM == NULL){
|
||||||
|
SCWrite(pCon,"ERROR: Did not find histogram memory",eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
nFrame = atoi(argv[3]);
|
||||||
|
return readHMFrame(pCon,pHM,nFrame);
|
||||||
|
} else if(strcmp(argv[1],"file") == 0){
|
||||||
|
if(argc < 6 ){
|
||||||
|
SCWrite(pCon,"ERROR: Insufficient number of arguments to PSDframe file",
|
||||||
|
eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
nFrame = atoi(argv[5]);
|
||||||
|
return readFileFrame(pCon,argv[2],argv[3],argv[4],nFrame);
|
||||||
|
} else {
|
||||||
|
SCWrite(pCon,"ERROR: subcommand to PSDframe not recognised",eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*======================================================================*/
|
||||||
|
int MakeFrameFunc(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||||
|
int argc, char *argv[]){
|
||||||
|
return AddCommand(pSics,"PSDframe",PSDFrameAction,NULL,NULL);
|
||||||
|
}
|
||||||
|
|
22
frame.h
Normal file
22
frame.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
A module implementing functionality for reading single time frames
|
||||||
|
from PSD time-of-flight datasets. This can be done either from
|
||||||
|
SINQHM histogram memories or from old data files visible from the
|
||||||
|
SICS server.
|
||||||
|
|
||||||
|
copyright: see file COPYRIGHT
|
||||||
|
|
||||||
|
Mark Koennecke, February-March 2003
|
||||||
|
*/
|
||||||
|
#ifndef SICSFRAME
|
||||||
|
#define SICSFRAME
|
||||||
|
|
||||||
|
int MakeFrameFunc(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||||
|
int argc, char *argv[]);
|
||||||
|
|
||||||
|
int PSDFrameAction(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||||
|
int argc, char *argv[]);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
32
frame.w
Normal file
32
frame.w
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
\subsection{Frame}
|
||||||
|
This module allows to retrieve data frames from a 3D histogram (PSD plus
|
||||||
|
time dimension). This can be done either from a Sinq histogram memory
|
||||||
|
and old data files visible from the SICS server.
|
||||||
|
|
||||||
|
This module has no data structure and only implements the usual
|
||||||
|
interpreter interface functions.
|
||||||
|
|
||||||
|
|
||||||
|
@o frame.h @{
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
A module implementing functionality for reading single time frames
|
||||||
|
from PSD time-of-flight datasets. This can be done either from
|
||||||
|
SINQHM histogram memories or from old data files visible from the
|
||||||
|
SICS server.
|
||||||
|
|
||||||
|
copyright: see file COPYRIGHT
|
||||||
|
|
||||||
|
Mark Koennecke, February-March 2003
|
||||||
|
*/
|
||||||
|
#ifndef SICSFRAME
|
||||||
|
#define SICSFRAME
|
||||||
|
|
||||||
|
int MakeFrameFunc(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||||
|
int argc, char *argv[]);
|
||||||
|
|
||||||
|
int PSDFrameAction(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||||
|
int argc, char *argv[]);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@}
|
54
hardsup/sinqhm.i
Normal file
54
hardsup/sinqhm.i
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
/*---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Internal header file for the SINQ histogram memory utility functions.
|
||||||
|
|
||||||
|
David Maden, Mark Koennecke April 1997
|
||||||
|
----------------------------------------------------------------------------*/
|
||||||
|
#ifndef SINQHMINTERNAL
|
||||||
|
#define SINQHMINTERNAL
|
||||||
|
#define MAXBANK 1
|
||||||
|
|
||||||
|
typedef struct __SBANK {
|
||||||
|
int iStart;
|
||||||
|
int iEnd;
|
||||||
|
int iFlag;
|
||||||
|
int iEdgeLength;
|
||||||
|
int iDelay;
|
||||||
|
unsigned int *iEdges;
|
||||||
|
} SBank, *pSBank;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct __SINQHM {
|
||||||
|
char *pHMComputer;
|
||||||
|
int iMasterPort;
|
||||||
|
int iMasterSocket;
|
||||||
|
int iClientPort;
|
||||||
|
int iClientSocket;
|
||||||
|
int iBinWidth;
|
||||||
|
int iLength;
|
||||||
|
int iRank;
|
||||||
|
int iPacket;
|
||||||
|
int iBanks;
|
||||||
|
int xSize, ySize;
|
||||||
|
int xOff, xFac;
|
||||||
|
int yOff, yFac;
|
||||||
|
SBank pBank[MAXBANK];
|
||||||
|
} SINQHM;
|
||||||
|
|
||||||
|
/*---------------------------- Type definitions, machine dependent--------*/
|
||||||
|
typedef short int SQint16; /* 16 bit integer */
|
||||||
|
typedef int SQint32; /* 32 bit integer */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int OpenMasterConnection(pSINQHM self);
|
||||||
|
static int GetMasterReply(pSINQHM self, struct rply_buff_struct *reply,
|
||||||
|
int iBufLen);
|
||||||
|
static int SendDAQCommand(pSINQHM self, int iCommand, int *iDaq);
|
||||||
|
|
||||||
|
|
||||||
|
static int SINQHMTimeBin(pSINQHM self, int iMode);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
25
make_gen
Normal file
25
make_gen
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# common part of the makefile for the PSI specific parts of SICS
|
||||||
|
#
|
||||||
|
# Mark Koennecke, June 2003
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
.SUFFIXES: .c .o .f
|
||||||
|
|
||||||
|
OBJ=psi.o buffer.o ruli.o dmc.o nxsans.o nextrics.o sps.o pimotor.o \
|
||||||
|
pipiezo.o sanswave.o faverage.o fowrite.o amor2t.o nxamor.o \
|
||||||
|
amorstat.o tasinit.o tasdrive.o tasutil.o tasscan.o swmotor.o \
|
||||||
|
polterwrite.o ecb.o frame.o el734driv.o el734dc.o ecbdriv.o \
|
||||||
|
ecbcounter.o el737driv.o sinqhmdriv.o tdchm.o velodorn.o \
|
||||||
|
velodornier.o docho.o sanscook.o tecsdriv.o itc4driv.o itc4.o\
|
||||||
|
bruker.o ltc11.o A1931.o dilludriv.o eurodriv.o slsmagnet.o \
|
||||||
|
el755driv.o amorscan.o serial.o scontroller.o
|
||||||
|
|
||||||
|
libpsi.a: $(OBJ)
|
||||||
|
- rm libpsi.a
|
||||||
|
ar cr libpsi.a $(OBJ)
|
||||||
|
ranlib libpsi.a
|
||||||
|
|
||||||
|
clean:
|
||||||
|
- rm *.a
|
||||||
|
- rm *.o
|
16
makefile_alpha
Normal file
16
makefile_alpha
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Makefile for the PSI specific part of SICS
|
||||||
|
# machine-dependent part for Tru64 Unix
|
||||||
|
#
|
||||||
|
# Mark Koennecke, June 2003
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
# the following line only for fortified version
|
||||||
|
#DFORTIFY=-DFORTIFY
|
||||||
|
#==========================================================================
|
||||||
|
|
||||||
|
HDFROOT=/data/lnslib
|
||||||
|
CC = cc
|
||||||
|
CFLAGS = -std1 -g $(DFORTIFY) -I.. -I$(HDFROOT)/include -DHDF4 -DHDF5 \
|
||||||
|
-Ihardsup
|
||||||
|
|
||||||
|
include make_gen
|
796
nxsans.c
Normal file
796
nxsans.c
Normal file
@ -0,0 +1,796 @@
|
|||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
N X S A N S
|
||||||
|
|
||||||
|
a module of utility functions which serve to write Nexus
|
||||||
|
data files for SANS.
|
||||||
|
|
||||||
|
Mark Koennecke, August 1997 - November 1998
|
||||||
|
|
||||||
|
Updated to support the larger detector resolution and possible
|
||||||
|
TOF and stroboscopic modes, Mark Koennecke, February 2001
|
||||||
|
|
||||||
|
Added additional monitors for stroboscopic gummi mode,
|
||||||
|
Mark Koennecke, September 2002
|
||||||
|
|
||||||
|
Copyright:
|
||||||
|
|
||||||
|
Labor fuer Neutronenstreuung
|
||||||
|
Paul Scherrer Institut
|
||||||
|
CH-5423 Villigen-PSI
|
||||||
|
|
||||||
|
|
||||||
|
The authors hereby grant permission to use, copy, modify, distribute,
|
||||||
|
and license this software and its documentation for any purpose, provided
|
||||||
|
that existing copyright notices are retained in all copies and that this
|
||||||
|
notice is included verbatim in any distributions. No written agreement,
|
||||||
|
license, or royalty fee is required for any of the authorized uses.
|
||||||
|
Modifications to this software may be copyrighted by their authors
|
||||||
|
and need not follow the licensing terms described here, provided that
|
||||||
|
the new terms are clearly indicated on the first page of each file where
|
||||||
|
they apply.
|
||||||
|
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
||||||
|
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||||
|
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
||||||
|
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
||||||
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
||||||
|
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
||||||
|
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
||||||
|
MODIFICATIONS.
|
||||||
|
----------------------------------------------------------------------------*/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "fortify.h"
|
||||||
|
#include "sics.h"
|
||||||
|
#include "sicsvar.h"
|
||||||
|
#include "napi.h"
|
||||||
|
#include "nxdict.h"
|
||||||
|
#include "modriv.h"
|
||||||
|
#include "motor.h"
|
||||||
|
#include "nxutil.h"
|
||||||
|
#include "nxdata.h"
|
||||||
|
#include "countdriv.h"
|
||||||
|
#include "counter.h"
|
||||||
|
#include "danu.h"
|
||||||
|
#include "HistMem.h"
|
||||||
|
#include "velo.h"
|
||||||
|
#include "sps.h"
|
||||||
|
#include "udpquieck.h"
|
||||||
|
#include "mumo.h"
|
||||||
|
#include "sanswave.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define HISTNAME "banana"
|
||||||
|
#define SAMPLETABLE "sampletable"
|
||||||
|
|
||||||
|
static int gummiFlag = 0; /* a flag indicating stroboscopic, or gummi mode */
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
static void SNError(void *pData, char *text)
|
||||||
|
{
|
||||||
|
SConnection *pCon;
|
||||||
|
|
||||||
|
assert(pData);
|
||||||
|
pCon = (SConnection *)pData;
|
||||||
|
SCWrite(pCon,text,eError);
|
||||||
|
}
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
NXhandle SNXStartSANS(SConnection *pCon, SicsInterp *pSics)
|
||||||
|
{
|
||||||
|
NXhandle pFile = NULL;
|
||||||
|
char *filename = NULL;
|
||||||
|
pSicsVariable pVar = NULL;
|
||||||
|
int iStat;
|
||||||
|
char pBueffel[512];
|
||||||
|
|
||||||
|
/* get a filename */
|
||||||
|
filename = SNXMakeFileName(pSics,pCon);
|
||||||
|
if(!filename)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a Nexus file */
|
||||||
|
NXopen(filename,NXACC_CREATE,&pFile);
|
||||||
|
if(!pFile)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"ERROR: cannot create data file ",eError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tell Uwe User what we are doing */
|
||||||
|
sprintf(pBueffel,"Writing %s ......",filename);
|
||||||
|
SCWrite(pCon,pBueffel,eWarning);
|
||||||
|
|
||||||
|
/* store global attributes */
|
||||||
|
iStat = NXputattr(pFile,"file_name",filename,
|
||||||
|
strlen(filename)+1,NX_CHAR);
|
||||||
|
if(iStat == NX_ERROR)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"ERROR: writing file_name attribute to Nexus file",eError);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* throw away filename, no longer needed */
|
||||||
|
free(filename);
|
||||||
|
|
||||||
|
/* write creation time */
|
||||||
|
SNXFormatTime(pBueffel,512);
|
||||||
|
iStat = NXputattr(pFile,"file_time",pBueffel,
|
||||||
|
strlen(pBueffel)+1,NX_CHAR);
|
||||||
|
if(iStat == NX_ERROR)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"ERROR: writing date attribute to Nexus file",eError);
|
||||||
|
}
|
||||||
|
pVar = FindVariable(pSics,"instrument");
|
||||||
|
if(pVar)
|
||||||
|
{
|
||||||
|
iStat = NXputattr(pFile,"instrument",pVar->text,
|
||||||
|
strlen(pVar->text)+1,NX_CHAR);
|
||||||
|
if(iStat == NX_ERROR)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"ERROR: writing instrument attribute to Nexus file",eError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pVar = NULL;
|
||||||
|
pVar = FindVariable(pSics,"user");
|
||||||
|
if(pVar)
|
||||||
|
{
|
||||||
|
iStat = NXputattr(pFile,"owner",pVar->text,
|
||||||
|
strlen(pVar->text)+1,NX_CHAR);
|
||||||
|
if(iStat == NX_ERROR)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"ERROR: writing owner attribute to Nexus file",eError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pVar = NULL;
|
||||||
|
pVar = FindVariable(pSics,"adress");
|
||||||
|
if(pVar)
|
||||||
|
{
|
||||||
|
iStat = NXputattr(pFile,"owner_adress",pVar->text,
|
||||||
|
strlen(pVar->text)+1,NX_CHAR);
|
||||||
|
if(iStat == NX_ERROR)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"ERROR: writing owner_adress attribute to Nexus file",eError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pVar = NULL;
|
||||||
|
pVar = FindVariable(pSics,"phone");
|
||||||
|
if(pVar)
|
||||||
|
{
|
||||||
|
iStat = NXputattr(pFile,"owner_telephone_number",pVar->text,
|
||||||
|
strlen(pVar->text)+1,NX_CHAR);
|
||||||
|
if(iStat == NX_ERROR)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"ERROR: writing owner_telephone_number attribute to Nexus file",eError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pVar = NULL;
|
||||||
|
pVar = FindVariable(pSics,"fax");
|
||||||
|
if(pVar)
|
||||||
|
{
|
||||||
|
iStat = NXputattr(pFile,"owner_fax_number",pVar->text,
|
||||||
|
strlen(pVar->text)+1,NX_CHAR);
|
||||||
|
if(iStat == NX_ERROR)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"ERROR: writing owner_fax_number attribute to Nexus file",eError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pVar = NULL;
|
||||||
|
pVar = FindVariable(pSics,"email");
|
||||||
|
if(pVar)
|
||||||
|
{
|
||||||
|
iStat = NXputattr(pFile,"owner_email",pVar->text,
|
||||||
|
strlen(pVar->text)+1,NX_CHAR);
|
||||||
|
if(iStat == NX_ERROR)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"ERROR: writing owner_email attribute to Nexus file",eError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pVar = NULL;
|
||||||
|
return pFile;
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
int SNMakeSANS(SConnection *pCon, SicsInterp *pSics, NXdict pDict)
|
||||||
|
{
|
||||||
|
NXhandle Nfil = NULL;
|
||||||
|
char pBueffel[512];
|
||||||
|
float fVal;
|
||||||
|
int iVal, iSet;
|
||||||
|
int32 iAxis[256];
|
||||||
|
int i, iRet;
|
||||||
|
long lVal;
|
||||||
|
HistInt *lData = NULL;
|
||||||
|
const float *fTime = NULL;
|
||||||
|
CommandList *pCom = NULL;
|
||||||
|
pHistMem self = NULL;
|
||||||
|
CounterMode eMode;
|
||||||
|
pVelSel pVelo = NULL;
|
||||||
|
pSPS pSiem = NULL;
|
||||||
|
const char *pNamPos = NULL;
|
||||||
|
float fRot, fTilt, fLambda;
|
||||||
|
pDummy pDum;
|
||||||
|
pIDrivable pDrive;
|
||||||
|
int iDim[MAXDIM], nDim, histSize,iStart;
|
||||||
|
|
||||||
|
/* start file */
|
||||||
|
Nfil = SNXStartSANS(pCon,pSics);
|
||||||
|
if(!Nfil)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
during all this, no extensive error checking will be done,
|
||||||
|
just write the error and continue, save at all cost
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* put all this global information */
|
||||||
|
SNXSPutVariable(pSics,pCon,Nfil,pDict,"etitle","title");
|
||||||
|
SNXSPutVariable(pSics,pCon,Nfil,pDict,"etime","starttime");
|
||||||
|
SNXFormatTime(pBueffel,511);
|
||||||
|
NXDputalias(Nfil,pDict,"endtime",pBueffel);
|
||||||
|
strcpy(pBueffel,"SANS at SINQ,PSI");
|
||||||
|
NXDputalias(Nfil,pDict,"iname",pBueffel);
|
||||||
|
strcpy(pBueffel,"SINQ at PSI,Villigen, Switzerland");
|
||||||
|
NXDputalias(Nfil,pDict,"sname",pBueffel);
|
||||||
|
strcpy(pBueffel,"Spallation");
|
||||||
|
NXDputalias(Nfil,pDict,"stype",pBueffel);
|
||||||
|
|
||||||
|
/* put the velocity selector data */
|
||||||
|
NXDputalias(Nfil,pDict,"vname","Dornier Velocity Selector");
|
||||||
|
|
||||||
|
fRot = 0.;
|
||||||
|
fTilt = 0.;
|
||||||
|
pCom = FindCommand(pSics,"nvs");
|
||||||
|
if(pCom)
|
||||||
|
{
|
||||||
|
pVelo = (pVelSel)pCom->pData;
|
||||||
|
if(!pVelo)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: Velocity Selctor not found",eWarning);
|
||||||
|
}
|
||||||
|
iRet = VSGetRotation(pVelo,&fVal);
|
||||||
|
if(!iRet)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: failed to read velocity selector speed",
|
||||||
|
eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fRot = fVal;
|
||||||
|
NXDputalias(Nfil,pDict,"vrot",&fVal);
|
||||||
|
}
|
||||||
|
iRet = VSGetTilt(pVelo,&fTilt);
|
||||||
|
if(!iRet)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: failed to read velocity selector tilt angle",eWarning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"vtilt","tilt");
|
||||||
|
CalculateLambda(fRot, fTilt, &fLambda);
|
||||||
|
NXDputalias(Nfil,pDict,"vlambda",&fLambda);
|
||||||
|
|
||||||
|
|
||||||
|
/* monitor 1 */
|
||||||
|
pCom = FindCommand(pSics,HISTNAME);
|
||||||
|
if(!pCom)
|
||||||
|
{
|
||||||
|
sprintf(pBueffel,"ERROR: histogram memory %s not found",HISTNAME);
|
||||||
|
SCWrite(pCon,pBueffel,eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
self = (pHistMem)pCom->pData;
|
||||||
|
assert(self);
|
||||||
|
lVal = GetHistMonitor(self,0,pCon);
|
||||||
|
iVal = (int32)lVal;
|
||||||
|
NXDputalias(Nfil,pDict,"m1counts",&iVal);
|
||||||
|
lVal = GetHistMonitor(self,4,pCon);
|
||||||
|
iVal = (int32)lVal;
|
||||||
|
NXDputalias(Nfil,pDict,"pbcounts",&iVal);
|
||||||
|
|
||||||
|
/* the collimator */
|
||||||
|
pCom = FindCommand(pSics,"sps2");
|
||||||
|
if(!pCom)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: sps-unit for reading collimator NOT found",
|
||||||
|
eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pSiem = (pSPS)pCom->pData;
|
||||||
|
if(!pSiem)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: sps-unit for reading collimator NOT found",
|
||||||
|
eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iRet = SPSGetSANS(pSiem,&fVal);
|
||||||
|
if(iRet <= 0)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: Failed to read SPS",eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NXDputalias(Nfil,pDict,"colli",&fVal);
|
||||||
|
}
|
||||||
|
/* as we got the sps, get the attenuator as well */
|
||||||
|
iRet = SPSGetStatus(pSiem,38,&iSet);
|
||||||
|
if(iRet <0)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: Failed to read SPS",eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(iSet)
|
||||||
|
{
|
||||||
|
iVal = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iRet = SPSGetStatus(pSiem,39,&iSet);
|
||||||
|
if(iRet <0)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: Failed to read SPS",eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(iSet)
|
||||||
|
{
|
||||||
|
iVal = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iRet = SPSGetStatus(pSiem,40,&iSet);
|
||||||
|
if(iRet <0)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: Failed to read SPS",eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(iSet)
|
||||||
|
{
|
||||||
|
iVal = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iRet = SPSGetStatus(pSiem,41,&iSet);
|
||||||
|
if(iRet <0)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: Failed to read SPS",eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(iSet)
|
||||||
|
{
|
||||||
|
iVal = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iRet = SPSGetStatus(pSiem,42,&iSet);
|
||||||
|
if(iRet <0)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: Failed to read SPS",eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(iSet)
|
||||||
|
{
|
||||||
|
iVal = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iRet = SPSGetStatus(pSiem,43,&iSet);
|
||||||
|
if(iRet <0)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: Failed to read SPS",eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(iSet)
|
||||||
|
{
|
||||||
|
iVal = 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NXDputalias(Nfil,pDict,"atti",&iVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the sample */
|
||||||
|
SNXSPutVariable(pSics,pCon,Nfil,pDict,"san","sample");
|
||||||
|
SNXSPutVariable(pSics,pCon,Nfil,pDict,"saenv","environment");
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"sax","sax");
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"say","say");
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"saz","saz");
|
||||||
|
SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"saxn","sax");
|
||||||
|
SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"sayn","say");
|
||||||
|
SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"sazn","saz");
|
||||||
|
|
||||||
|
|
||||||
|
/* goniometer */
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"gphi","gphi");
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"gtheta","gtheta");
|
||||||
|
SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"gphin","gphi");
|
||||||
|
SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"gthetan","gtheta");
|
||||||
|
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"saom","som");
|
||||||
|
SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"saomn","som");
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"sapos","spos");
|
||||||
|
SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"saposn","spos");
|
||||||
|
pCom = FindCommand(pSics,SAMPLETABLE);
|
||||||
|
if(pCom)
|
||||||
|
{
|
||||||
|
if(pCom->pData)
|
||||||
|
{
|
||||||
|
pNamPos = FindNamPos((pMulMot)pCom->pData,pCon);
|
||||||
|
if(pNamPos)
|
||||||
|
{
|
||||||
|
NXDputalias(Nfil,pDict,"sanampos",(char *)pNamPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* write sample environment here */
|
||||||
|
pCom = FindCommand(pSics,"temperature");
|
||||||
|
if(pCom)
|
||||||
|
{
|
||||||
|
pDum = (pDummy)pCom->pData;
|
||||||
|
pDrive = pDum->pDescriptor->GetInterface(pDum,DRIVEID);
|
||||||
|
if(pDrive) /* a proper environment device */
|
||||||
|
{
|
||||||
|
fVal = pDrive->GetValue(pDum,pCon);
|
||||||
|
NXDputalias(Nfil,pDict,"satemp",&fVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pCom = FindCommand(pSics,"magnet");
|
||||||
|
if(pCom)
|
||||||
|
{
|
||||||
|
pDum = (pDummy)pCom->pData;
|
||||||
|
pDrive = pDum->pDescriptor->GetInterface(pDum,DRIVEID);
|
||||||
|
if(pDrive) /* a proper environment device */
|
||||||
|
{
|
||||||
|
fVal = pDrive->GetValue(pDum,pCon);
|
||||||
|
NXDputalias(Nfil,pDict,"samag",&fVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* magnet motors. This instrument has motorized magnets crawling
|
||||||
|
through the hall */
|
||||||
|
pCom = FindCommand(pSics,"mom");
|
||||||
|
if(pCom)
|
||||||
|
{
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"mom","mom");
|
||||||
|
}
|
||||||
|
pCom = FindCommand(pSics,"mz");
|
||||||
|
if(pCom)
|
||||||
|
{
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"mz","mz");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* put Beam Stop */
|
||||||
|
/* read beamstop number */
|
||||||
|
iVal = 1;
|
||||||
|
pCom = FindCommand(pSics,"sps1");
|
||||||
|
if(!pCom)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: sps-unit for reading beamstop NOT found",eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pSiem = (pSPS)pCom->pData;
|
||||||
|
if(!pSiem)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: sps-unit for reading beamstop NOT found",eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iRet = SPSGetStatus(pSiem,8,&iSet);
|
||||||
|
if(iRet <0)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: Failed to read SPS",eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(iSet)
|
||||||
|
{
|
||||||
|
iVal = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iRet = SPSGetStatus(pSiem,9,&iSet);
|
||||||
|
if(iRet <0)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: Failed to read SPS",eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(iSet)
|
||||||
|
{
|
||||||
|
iVal = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iRet = SPSGetStatus(pSiem,10,&iSet);
|
||||||
|
if(iRet <0)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: Failed to read SPS",eWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(iSet)
|
||||||
|
{
|
||||||
|
iVal = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NXDputalias(Nfil,pDict,"bst",&iVal);
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"vsx","BeamStopX");
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"vsy","BeamStopY");
|
||||||
|
SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"vsxnull","BeamStopX");
|
||||||
|
SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"vsynull","BeamStopY");
|
||||||
|
|
||||||
|
/* what this is all about: the detector */
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"ddx","DetectorX");
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"ddy","DetectorY");
|
||||||
|
SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"ddxn","DetectorX");
|
||||||
|
SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"ddyn","DetectorY");
|
||||||
|
SNXSPutMotor(pSics,pCon,Nfil,pDict,"ddchi","DetectorRotation");
|
||||||
|
pCom = FindCommand(pSics,HISTNAME);
|
||||||
|
if(!pCom)
|
||||||
|
{
|
||||||
|
sprintf(pBueffel,"ERROR: histogram memory %s not found",HISTNAME);
|
||||||
|
SCWrite(pCon,pBueffel,eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
self = (pHistMem)pCom->pData;
|
||||||
|
assert(self);
|
||||||
|
eMode = GetHistCountMode(self);
|
||||||
|
if(eMode == eTimer)
|
||||||
|
{
|
||||||
|
strcpy(pBueffel,"Timer");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy(pBueffel,"Monitor");
|
||||||
|
}
|
||||||
|
NXDputalias(Nfil,pDict,"ddm",pBueffel);
|
||||||
|
fVal = GetHistPreset(self);
|
||||||
|
NXDputalias(Nfil,pDict,"ddp",&fVal);
|
||||||
|
lVal = GetHistMonitor(self,1,pCon);
|
||||||
|
iVal = (int32)lVal;
|
||||||
|
NXDputalias(Nfil,pDict,"ddmo",&iVal);
|
||||||
|
fVal = GetHistCountTime(self,pCon);
|
||||||
|
NXDputalias(Nfil,pDict,"ddtime",&fVal);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Deal with actual histogram. Due to stroboscopic modes and the
|
||||||
|
new detector electronics we need to find out about the size
|
||||||
|
ourselves now. And possibly write time binning information.
|
||||||
|
*/
|
||||||
|
GetHistDim(self, iDim,&nDim);
|
||||||
|
/*
|
||||||
|
handle time binning
|
||||||
|
*/
|
||||||
|
fTime = GetHistTimeBin(self,&iVal);
|
||||||
|
if(iVal > 2)
|
||||||
|
{
|
||||||
|
NXDputalias(Nfil,pDict,"ddtb",(void *)fTime);
|
||||||
|
nDim = 3;
|
||||||
|
iDim[2] = iVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
histSize = 1;
|
||||||
|
for(i = 0; i < nDim; i++)
|
||||||
|
{
|
||||||
|
histSize *= iDim[i];
|
||||||
|
}
|
||||||
|
lData = (HistInt *)malloc(histSize*sizeof(HistInt));
|
||||||
|
if(!lData)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"ERROR: out of memory, FAILED to store data, file corrupt",
|
||||||
|
eError);
|
||||||
|
NXclose(&Nfil);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
GetHistogram(self,pCon,0,0,histSize,lData,histSize*sizeof(HistInt));
|
||||||
|
sprintf(pBueffel," %d ",iDim[0]);
|
||||||
|
NXDupdate(pDict,"dim1",pBueffel);
|
||||||
|
sprintf(pBueffel," %d ",iDim[1]);
|
||||||
|
NXDupdate(pDict,"dim2",pBueffel);
|
||||||
|
if(nDim == 2)
|
||||||
|
{
|
||||||
|
sprintf(pBueffel," -rank 2 -dim {%d,%d} ", iDim[0], iDim[1]);
|
||||||
|
NXDupdate(pDict,"countdim",pBueffel);
|
||||||
|
}
|
||||||
|
else if (nDim == 3)
|
||||||
|
{
|
||||||
|
sprintf(pBueffel," -rank 3 -dim {%d,%d,%d} ", iDim[0], iDim[1],
|
||||||
|
iDim[2]);
|
||||||
|
NXDupdate(pDict,"countdim",pBueffel);
|
||||||
|
sprintf(pBueffel," %d ",iDim[2]);
|
||||||
|
NXDupdate(pDict,"timedim",pBueffel);
|
||||||
|
}
|
||||||
|
NXDputalias(Nfil,pDict,"ddcounts",lData);
|
||||||
|
free(lData);
|
||||||
|
|
||||||
|
/* write x and y axis */
|
||||||
|
for(i = 0; i < iDim[0]; i++)
|
||||||
|
{
|
||||||
|
iAxis[i] = i;
|
||||||
|
}
|
||||||
|
NXDputalias(Nfil,pDict,"ddcx",iAxis);
|
||||||
|
for(i = 0; i < iDim[1]; i++)
|
||||||
|
{
|
||||||
|
iAxis[i] = i;
|
||||||
|
}
|
||||||
|
NXDputalias(Nfil,pDict,"ddcy",iAxis);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
write gummi monitors when apropriate
|
||||||
|
*/
|
||||||
|
if(nDim == 3 && gummiFlag != 0)
|
||||||
|
{
|
||||||
|
histSize = 3*iDim[2];
|
||||||
|
lData = (HistInt *)malloc(histSize*sizeof(HistInt));
|
||||||
|
if(lData == NULL)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"WARNING: failed to allocate memory for monitors",
|
||||||
|
eWarning);
|
||||||
|
} else {
|
||||||
|
memset(lData,0,histSize*sizeof(HistInt));
|
||||||
|
iStart = iDim[0]*iDim[1]*iDim[2];
|
||||||
|
GetHistogramDirect(self,pCon,0,iStart,iStart+histSize,
|
||||||
|
lData,histSize*sizeof(HistInt));
|
||||||
|
NXDputalias(Nfil,pDict,"gummimon1",lData);
|
||||||
|
NXDputalias(Nfil,pDict,"gummimon2",lData+iDim[2]);
|
||||||
|
NXDputalias(Nfil,pDict,"gummimon3",lData+2*iDim[2]);
|
||||||
|
free(lData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
write detector temperature. It is a hot one............
|
||||||
|
*/
|
||||||
|
if(pSiem)
|
||||||
|
{
|
||||||
|
iRet = SPSGetADC(pSiem,1,&iVal);
|
||||||
|
if(iRet)
|
||||||
|
{
|
||||||
|
fVal = iVal/269.9;
|
||||||
|
NXDputalias(Nfil,pDict,"ddtemp",&fVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do the linking in th data vgroup */
|
||||||
|
NXDaliaslink(Nfil,pDict,"dan","ddcounts");
|
||||||
|
NXDaliaslink(Nfil,pDict,"dan","ddcx");
|
||||||
|
NXDaliaslink(Nfil,pDict,"dan","ddcy");
|
||||||
|
NXDaliaslink(Nfil,pDict,"dan","ddmo");
|
||||||
|
NXDaliaslink(Nfil,pDict,"dan","vlambda");
|
||||||
|
if(nDim == 3)
|
||||||
|
{
|
||||||
|
NXDaliaslink(Nfil,pDict,"dan","ddtb");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send quieck message for automatic copying*/
|
||||||
|
i = 131;
|
||||||
|
iVal = NX_CHAR;
|
||||||
|
NXgetattr(Nfil,"file_name",pBueffel,&i,&iVal);
|
||||||
|
SendQuieck(QUIECK,pBueffel);
|
||||||
|
/* close this and go ............. */
|
||||||
|
NXclose(&Nfil);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*------------------- The Mechanics for setting Up ------------------------*/
|
||||||
|
typedef struct {
|
||||||
|
pObjectDescriptor pDes;
|
||||||
|
NXdict pDict;
|
||||||
|
} DictStruct, *pDictStruct;
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
static pDictStruct MakeDictStruct(char *pFile)
|
||||||
|
{
|
||||||
|
pDictStruct pNew = NULL;
|
||||||
|
int iRet;
|
||||||
|
|
||||||
|
pNew = (pDictStruct)malloc(sizeof(DictStruct));
|
||||||
|
if(!pNew)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(pNew,0,sizeof(DictStruct));
|
||||||
|
pNew->pDes = CreateDescriptor("StoreData");
|
||||||
|
if(!pNew->pDes)
|
||||||
|
{
|
||||||
|
free(pNew);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
iRet = NXDinitfromfile(pFile,&(pNew->pDict));
|
||||||
|
if(iRet != NX_OK)
|
||||||
|
{
|
||||||
|
DeleteDescriptor(pNew->pDes);
|
||||||
|
free(pNew);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return pNew;
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
static void KillDictStruct(void *pData)
|
||||||
|
{
|
||||||
|
pDictStruct self = NULL;
|
||||||
|
|
||||||
|
self = (pDictStruct)pData;
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
if(self->pDes)
|
||||||
|
{
|
||||||
|
DeleteDescriptor(self->pDes);
|
||||||
|
}
|
||||||
|
if(self->pDict)
|
||||||
|
{
|
||||||
|
NXDclose(self->pDict,NULL);
|
||||||
|
}
|
||||||
|
free(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
int SNStoreSANS(SConnection *pCon, SicsInterp *pSics, void *pData, int argc,
|
||||||
|
char *argv[])
|
||||||
|
|
||||||
|
{
|
||||||
|
char pBueffel[80];
|
||||||
|
pDictStruct self = NULL;
|
||||||
|
self = (pDictStruct)pData;
|
||||||
|
|
||||||
|
assert(self);
|
||||||
|
assert(pCon);
|
||||||
|
assert(pSics);
|
||||||
|
|
||||||
|
if(argc > 1){
|
||||||
|
strtolower(argv[1]);
|
||||||
|
if(strcmp(argv[1],"gummi") == 0){
|
||||||
|
if(argc > 2){
|
||||||
|
if(!SCMatchRights(pCon,usMugger)){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
gummiFlag = atoi(argv[2]);
|
||||||
|
SCSendOK(pCon);
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
sprintf(pBueffel,"%s.gummi = %d",argv[0], gummiFlag);
|
||||||
|
SCWrite(pCon,pBueffel,eValue);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SNMakeSANS(pCon,pSics,self->pDict);
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
int InitSANS(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||||
|
int argc, char *argv[])
|
||||||
|
{
|
||||||
|
pDictStruct pNew = NULL;
|
||||||
|
char pBueffel[512];
|
||||||
|
|
||||||
|
if(argc < 2)
|
||||||
|
{
|
||||||
|
SCWrite(pCon,"ERROR: not enough arguments for IniSANS",eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNew = MakeDictStruct(argv[1]);
|
||||||
|
if(!pNew)
|
||||||
|
{
|
||||||
|
sprintf(pBueffel,"ERROR: failed to initialise NXDDL from file %s",
|
||||||
|
argv[1]);
|
||||||
|
SCWrite(pCon,pBueffel,eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
AddCommand(pSics,"StoreData",SNStoreSANS,KillDictStruct,pNew);
|
||||||
|
return 1;
|
||||||
|
}
|
17
nxsans.h
Normal file
17
nxsans.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
N X S A N S
|
||||||
|
|
||||||
|
Prototypes for some more useful functions from the SANS data writing
|
||||||
|
module which may ne used in other parts of SICS.
|
||||||
|
|
||||||
|
Mark Koennecke, December 1997
|
||||||
|
---------------------------------------------------------------------------*/
|
||||||
|
#ifndef NXSANS
|
||||||
|
#define NXSANS
|
||||||
|
int InitSANS(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||||
|
int argc, char *argv[]);
|
||||||
|
int SNStoreSANS(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||||
|
int argc, char *argv[]);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
282
scontroller.c
Normal file
282
scontroller.c
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Some code to connect to a serial port through the SINQ system.
|
||||||
|
|
||||||
|
Just a wrapper around serialsinq derived from David Maden's
|
||||||
|
EL734 routines.
|
||||||
|
|
||||||
|
You are free to use and modify this software for noncommercial
|
||||||
|
usage.
|
||||||
|
|
||||||
|
No warranties or liabilities of any kind taken by me or my employer
|
||||||
|
|
||||||
|
Very primitive device to send commands to a motor from Tcl
|
||||||
|
|
||||||
|
Modified version for use within SICS.
|
||||||
|
----------------------------------------------------------------------------*/
|
||||||
|
#include "sinq_prototypes.h"
|
||||||
|
/* #include <timers.h>*/
|
||||||
|
#include <tcl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "rs232c_def.h"
|
||||||
|
#include "el734_def.h"
|
||||||
|
#include "psi/hardsup/serialsinq.h"
|
||||||
|
#include "sics.h"
|
||||||
|
|
||||||
|
#define False 0
|
||||||
|
#define True 1
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------
|
||||||
|
Tcl has a high niceness level. It deletes a command properly when
|
||||||
|
exiting, reinitializing etc. I use this facility to kill off the
|
||||||
|
motor initialised in Controller.
|
||||||
|
---------------------------------------------------------------------------*/
|
||||||
|
EXTERN void SerialMurder(ClientData pData)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
NetReadRemoveUserSocket(pServ->pReader, SerialGetSocket(&(pData)));
|
||||||
|
*/
|
||||||
|
SerialClose(&(pData));
|
||||||
|
free(pData);
|
||||||
|
}
|
||||||
|
/*------------------ a forward declaration -----------------------------*/
|
||||||
|
EXTERN int SurielSend(ClientData clientData, Tcl_Interp *interp,
|
||||||
|
int argc, char *argv[]);
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
Controller is the main entry point for this stuff. It connects to a motor
|
||||||
|
and, on success, creates a new command with the name of the motor.
|
||||||
|
Syntax:
|
||||||
|
Controller name host port channel
|
||||||
|
---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int Controller(ClientData clientData, Tcl_Interp *interp,
|
||||||
|
int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int iRet;
|
||||||
|
int iPort, iChannel, iMotor;
|
||||||
|
char *pErr = NULL;
|
||||||
|
char pBueffel[80];
|
||||||
|
void **pData = NULL;
|
||||||
|
|
||||||
|
/* check arguments */
|
||||||
|
if(argc < 5)
|
||||||
|
{
|
||||||
|
Tcl_AppendResult(interp,
|
||||||
|
" Insufficient arguments: Controller name host port channel index"
|
||||||
|
, (char *) NULL);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert arguments */
|
||||||
|
iRet = Tcl_GetInt(interp,argv[3],&iPort);
|
||||||
|
if(iRet == TCL_ERROR)
|
||||||
|
{
|
||||||
|
Tcl_AppendResult(interp,"Need integer value for port",
|
||||||
|
(char *)NULL);
|
||||||
|
return iRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
iRet = Tcl_GetInt(interp,argv[4],&iChannel);
|
||||||
|
if(iRet == TCL_ERROR)
|
||||||
|
{
|
||||||
|
Tcl_AppendResult(interp,"Need integer value for channel",
|
||||||
|
(char *)NULL);
|
||||||
|
return iRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
iMotor = 1;
|
||||||
|
|
||||||
|
|
||||||
|
/* make a new pointer, initialise EL734st */
|
||||||
|
pData = malloc(sizeof(void *));
|
||||||
|
if(pData ==NULL)
|
||||||
|
{
|
||||||
|
Tcl_AppendResult(interp,"No memory in SerialSinq",NULL);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for optional force flag */
|
||||||
|
if(argc > 5)
|
||||||
|
{
|
||||||
|
iRet = SerialForceOpen(pData, argv[2],iPort,iChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open the motor, finally */
|
||||||
|
iRet = SerialOpen(pData, argv[2],iPort,iChannel);
|
||||||
|
if(iRet == 1) /* success */
|
||||||
|
{
|
||||||
|
/* handle TCL, create new command: the serial line */
|
||||||
|
Tcl_CreateCommand(interp,strdup(argv[1]),SurielSend,
|
||||||
|
*pData,SerialMurder);
|
||||||
|
strcpy(pBueffel,argv[1]);
|
||||||
|
Tcl_AppendResult(interp,strdup(argv[1]),(char *)NULL);
|
||||||
|
if(pServ->pReader != NULL)
|
||||||
|
{
|
||||||
|
NetReadRegisterUserSocket(pServ->pReader,
|
||||||
|
SerialGetSocket(pData));
|
||||||
|
}
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SerialError(iRet,pBueffel,79);
|
||||||
|
Tcl_AppendResult(interp,pBueffel,(char *) NULL);
|
||||||
|
SerialClose(pData);
|
||||||
|
free(pData);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
Now, this interprets some commands:
|
||||||
|
-tmo val
|
||||||
|
will set a timeout value for the connection. Everything
|
||||||
|
else will be concatenated and sent to the device.
|
||||||
|
-sendterm text
|
||||||
|
defines the terminator which will be appended automatically
|
||||||
|
to each command.
|
||||||
|
-replyterm text
|
||||||
|
sets the expected reply terminator from the Macintosh
|
||||||
|
Serial Port server.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------*/
|
||||||
|
EXTERN int SurielSend(ClientData clientData, Tcl_Interp *interp,
|
||||||
|
int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char pBueffel[256];
|
||||||
|
char pAnswer[256];
|
||||||
|
char *pErr = NULL;
|
||||||
|
int iRet, iMSR;
|
||||||
|
int i;
|
||||||
|
void *pData;
|
||||||
|
|
||||||
|
pData = clientData;
|
||||||
|
|
||||||
|
if(argc >= 2)
|
||||||
|
{
|
||||||
|
if(strcmp(argv[1],"-tmo") == 0)
|
||||||
|
{
|
||||||
|
if(argc >= 3)
|
||||||
|
{
|
||||||
|
iRet = Tcl_GetInt(interp,argv[2],&iMSR);
|
||||||
|
if(iRet != TCL_OK)
|
||||||
|
{
|
||||||
|
sprintf(pBueffel,"%s is not a valid number",argv[2]);
|
||||||
|
Tcl_AppendResult(interp,pBueffel,NULL);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
SerialConfig(&(pData),iMSR);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Tcl_AppendResult(interp, "Expected parameter after -tmo",NULL);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(strcmp(argv[1],"-sendterm") == 0)
|
||||||
|
{
|
||||||
|
if(argc < 3)
|
||||||
|
{
|
||||||
|
Tcl_AppendResult(interp, "Expected parameter after -tmo",NULL);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
iRet = SerialSendTerm(&(pData),argv[2]);
|
||||||
|
if(iRet != 1)
|
||||||
|
{
|
||||||
|
Tcl_AppendResult(interp,"To many characters for terminator",NULL);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
else if(strcmp(argv[1],"-replyterm") == 0)
|
||||||
|
{
|
||||||
|
if(argc < 3)
|
||||||
|
{
|
||||||
|
Tcl_AppendResult(interp, "Expected parameter after -tmo",NULL);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
iRet = SerialATerm(&(pData),argv[2]);
|
||||||
|
if(!iRet)
|
||||||
|
{
|
||||||
|
Tcl_AppendResult(interp,"To many characters for terminator",NULL);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
else if(strcmp(argv[1],"-put") == 0)
|
||||||
|
{
|
||||||
|
NetReadResetUser(pServ->pReader,SerialGetSocket(&(pData)));
|
||||||
|
if(argc > 2)
|
||||||
|
{
|
||||||
|
strcpy(pBueffel,argv[2]);
|
||||||
|
}
|
||||||
|
for(i = 3; i < argc; i++)
|
||||||
|
{
|
||||||
|
strcat(pBueffel," ");
|
||||||
|
strcat(pBueffel,argv[i]);
|
||||||
|
}
|
||||||
|
iRet = SerialSend(&(pData),pBueffel);
|
||||||
|
if(iRet != 1)
|
||||||
|
{
|
||||||
|
Tcl_AppendResult(interp,pAnswer,NULL);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
else if(strcmp(argv[1],"-readable") == 0)
|
||||||
|
{
|
||||||
|
iRet = NetReadReadable(pServ->pReader,SerialGetSocket(&(pData)));
|
||||||
|
if(iRet)
|
||||||
|
{
|
||||||
|
Tcl_AppendResult(interp,"1",NULL);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Tcl_AppendResult(interp,"0",NULL);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(strcmp(argv[1],"-get") == 0)
|
||||||
|
{
|
||||||
|
if(NetReadReadable(pServ->pReader,SerialGetSocket(&(pData))))
|
||||||
|
{
|
||||||
|
iRet = SerialReceive(&(pData),pAnswer, 255);
|
||||||
|
Tcl_AppendResult(interp,pAnswer,NULL);
|
||||||
|
if(iRet == 1)
|
||||||
|
{
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tcl_AppendResult(interp,"Not Readable",NULL);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(argc >= 2)
|
||||||
|
{
|
||||||
|
strcpy(pBueffel,argv[1]);
|
||||||
|
}
|
||||||
|
for(i = 2; i < argc; i++)
|
||||||
|
{
|
||||||
|
strcat(pBueffel," ");
|
||||||
|
strcat(pBueffel,argv[i]);
|
||||||
|
}
|
||||||
|
i = strlen(pBueffel);
|
||||||
|
iRet = SerialWriteRead(&(pData),pBueffel,pAnswer,254);
|
||||||
|
if(iRet != 1)
|
||||||
|
{
|
||||||
|
Tcl_AppendResult(interp,pAnswer,NULL);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
Tcl_AppendResult(interp,pAnswer,NULL);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
Reference in New Issue
Block a user