365 lines
10 KiB
C
365 lines
10 KiB
C
/*--------------------------------------------------------------------------
|
|
|
|
Some code to make EL737 COUNTERS as used at SINQ available in TCL.
|
|
Just a wrapper around David Maden's COUNTER 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
|
|
|
|
Mark Koennecke July 1996
|
|
----------------------------------------------------------------------------*/
|
|
#include "sinq_prototypes.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
/*
|
|
#include <timers.h>
|
|
*/
|
|
#include <tcl.h>
|
|
#include "el737_def.h"
|
|
|
|
#define True 1
|
|
#define False 0
|
|
|
|
typedef struct {
|
|
void *pData; /* EL737 open struct */
|
|
} EL737st;
|
|
|
|
EXTERN int EL737Action(ClientData pDat, Tcl_Interp * i, int a,
|
|
char *argv[]);
|
|
static void EL737Error2Text(char *pBuffer, int errcode);
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Tcl has a high niceness level. It deletes a command properly when
|
|
exiting, reinitializing etc. I use this facility to kill off the
|
|
counter initialised in CterEL737.
|
|
---------------------------------------------------------------------------*/
|
|
EXTERN void EL737Murder(ClientData pData)
|
|
{
|
|
EL737st *pTa = (EL737st *) pData;
|
|
EL737_Close(&(pTa->pData));
|
|
free(pData);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
CterEL737 is the main entry point for this stuff. It connects to a counter
|
|
and, on success, creates a new command with the name of the counter.
|
|
Syntax:
|
|
EL737 name host port channel
|
|
---------------------------------------------------------------------------*/
|
|
|
|
int CterEL737(ClientData clientData, Tcl_Interp * interp,
|
|
int argc, char *argv[])
|
|
{
|
|
int iRet;
|
|
EL737st *pEL737 = NULL;
|
|
int iPort, iChannel, iMotor;
|
|
char *pErr = NULL;
|
|
char pBueffel[80];
|
|
|
|
/* check arguments */
|
|
if (argc < 5) {
|
|
Tcl_AppendResult(interp,
|
|
" Insufficient arguments: CterEL737 name host port channel",
|
|
(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;
|
|
}
|
|
|
|
/* make a new pointer, initialise EL737st */
|
|
pEL737 = (EL737st *) malloc(sizeof(EL737st));
|
|
if (pEL737 == NULL) {
|
|
Tcl_AppendResult(interp, "No memory in EL734", NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
/* open the rotten Counter, finally */
|
|
iRet = EL737_Open(&(pEL737->pData), argv[2], iPort, iChannel);
|
|
if (iRet) { /* success */
|
|
/* handle TCL, create new command: the Counter */
|
|
Tcl_CreateCommand(interp, strdup(argv[1]), EL737Action,
|
|
(ClientData) pEL737, EL737Murder);
|
|
Tcl_AppendResult(interp, strdup(argv[1]), (char *) NULL);
|
|
return TCL_OK;
|
|
} else {
|
|
EL737_ErrInfo(&pErr, &iPort, &iChannel, &iMotor);
|
|
EL737Error2Text(pBueffel, iPort);
|
|
Tcl_AppendResult(interp, pBueffel, (char *) NULL);
|
|
free(pEL737);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
|
|
EL737 Action is the routine where commands send to the conter will
|
|
end up.
|
|
|
|
Syntax: timer starts counter with a preset value
|
|
counter wait val for counts or time and does
|
|
monitor not return before finished
|
|
|
|
timer starts counter with a preset value
|
|
counter start val for counts or time and
|
|
monitor returns immediatly
|
|
counter isDone returns True, false depending if
|
|
started run has ended or not
|
|
counter value gets counter values as a little list
|
|
consisting of:
|
|
{ counts monitor time }
|
|
counter Stop forces counter to stop
|
|
----------------------------------------------------------------------------*/
|
|
EXTERN int EL737Action(ClientData clientData, Tcl_Interp * interp,
|
|
int argc, char *argv[])
|
|
{
|
|
EL737st *pData = (EL737st *) clientData;
|
|
char pBueffel[132];
|
|
char pNumBuf[20];
|
|
char *pErr = NULL;
|
|
int iC1, iC2, iC3, iC4, iRS, iRet;
|
|
float fTime;
|
|
int iFlag = 0;
|
|
int iMode;
|
|
double dVal;
|
|
|
|
/* obviously we need at least a keyword! */
|
|
if (argc < 2) {
|
|
Tcl_AppendResult(interp, "No keyword given", NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
/* get values out */
|
|
if (strcmp(argv[1], "value") == 0) {
|
|
iRet = EL737_GetStatus(&(pData->pData), &iC1, &iC2, &iC3,
|
|
&iC4, &fTime, &iRS);
|
|
if (!iRet) {
|
|
EL737_ErrInfo(&pErr, &iC1, &iC2, &iC3);
|
|
EL737Error2Text(pBueffel, iC1);
|
|
Tcl_AppendResult(interp, pBueffel, (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
sprintf(pNumBuf, "%d", iC2);
|
|
Tcl_AppendElement(interp, pNumBuf);
|
|
sprintf(pNumBuf, "%d", iC1);
|
|
Tcl_AppendElement(interp, pNumBuf);
|
|
sprintf(pNumBuf, "%f", fTime);
|
|
Tcl_AppendElement(interp, pNumBuf);
|
|
return TCL_OK;
|
|
}
|
|
|
|
/* isDone ? */
|
|
if (strcmp(argv[1], "isDone") == 0) {
|
|
iRet = EL737_GetStatus(&(pData->pData), &iC1, &iC2, &iC3,
|
|
&iC4, &fTime, &iRS);
|
|
if (!iRet) {
|
|
EL737_ErrInfo(&pErr, &iC1, &iC2, &iC3);
|
|
EL737Error2Text(pBueffel, iC1);
|
|
Tcl_AppendResult(interp, pBueffel, (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
if (iRS == 0) { /* done is true */
|
|
sprintf(pNumBuf, "%d", True);
|
|
} else {
|
|
sprintf(pNumBuf, "%d", False);
|
|
}
|
|
Tcl_AppendResult(interp, pNumBuf, (char *) NULL);
|
|
return TCL_OK;
|
|
}
|
|
|
|
/* actual counting neutrons in two different modes */
|
|
if (strcmp(argv[1], "wait") == 0) {
|
|
iFlag = 2;
|
|
}
|
|
if (strcmp(argv[1], "start") == 0) {
|
|
iFlag = 1;
|
|
}
|
|
if (iFlag > 0) { /* we need to count */
|
|
if (argc < 4) { /* not enough arguments */
|
|
Tcl_AppendResult(interp, "Usage: ", argv[0], argv[1],
|
|
" timer or monitor val", NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
/* timer or monitor preset ? */
|
|
if (strcmp(argv[2], "timer") == 0) {
|
|
iMode = 1;
|
|
} else if (strcmp(argv[2], "monitor") == 0) {
|
|
iMode = 2;
|
|
} else {
|
|
Tcl_AppendResult(interp, "Usage: ", argv[0], argv[1],
|
|
" timer or monitor val", NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
/* get the preset value */
|
|
iRet = Tcl_GetDouble(interp, argv[3], &dVal);
|
|
if (iRet == TCL_ERROR) {
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
/* actual start collecting neutrons */
|
|
if (iMode == 1) {
|
|
iRet = EL737_StartTime(&(pData->pData), (float) dVal, &iRS);
|
|
} else {
|
|
iRet = EL737_StartCnt(&(pData->pData), (int) dVal, &iRS);
|
|
}
|
|
if (!iRet) {
|
|
EL737_ErrInfo(&pErr, &iC1, &iC2, &iC3);
|
|
EL737Error2Text(pBueffel, iC1);
|
|
Tcl_AppendResult(interp, pBueffel, (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
}
|
|
|
|
/* end of count startup code */
|
|
/* if apropriate: wait */
|
|
if (iFlag == 2) {
|
|
iRet = EL737_WaitIdle(&(pData->pData), &iC1, &iC2, &iC3, &iC4, &fTime);
|
|
if (!iRet) {
|
|
EL737_ErrInfo(&pErr, &iC1, &iC2, &iC3);
|
|
EL737Error2Text(pBueffel, iC1);
|
|
Tcl_AppendResult(interp, pBueffel, (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
return TCL_OK;
|
|
} else if (iFlag == 1) {
|
|
return TCL_OK;
|
|
}
|
|
|
|
/* the stop command */
|
|
if (strcmp(argv[1], "stop") == 0) {
|
|
iRet = EL737_Stop(&(pData->pData), &iC1, &iC2, &iC3,
|
|
&iC4, &fTime, &iRS);
|
|
if (!iRet) {
|
|
EL737_ErrInfo(&pErr, &iC1, &iC2, &iC3);
|
|
EL737Error2Text(pBueffel, iC1);
|
|
Tcl_AppendResult(interp, pBueffel, (char *) NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
return TCL_OK;
|
|
}
|
|
|
|
Tcl_AppendResult(interp, " obscure command: ", argv[1],
|
|
" not understood by EL737 counter", NULL);
|
|
return TCL_ERROR;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
|
|
EL737Error2Text converts between an EL734 error code to text
|
|
-----------------------------------------------------------------------------*/
|
|
void EL737Error2Text(char *pBuffer, int iErr)
|
|
{
|
|
switch (iErr) {
|
|
case -28:
|
|
strcpy(pBuffer, "EL737__BAD_ADR");
|
|
break;
|
|
case -8:
|
|
strcpy(pBuffer, "EL737__BAD_OVFL");
|
|
break;
|
|
case -30:
|
|
strcpy(pBuffer, "EL737__BAD_BSY");
|
|
break;
|
|
case -3:
|
|
strcpy(pBuffer, "EL737__BAD_SNTX");
|
|
break;
|
|
case -9:
|
|
strcpy(pBuffer, "EL737__BAD_CONNECT");
|
|
break;
|
|
case -23:
|
|
strcpy(pBuffer, "EL737__BAD_FLUSH");
|
|
break;
|
|
case -6:
|
|
strcpy(pBuffer, "EL734__BAD_DEV");
|
|
break;
|
|
case -10:
|
|
strcpy(pBuffer, "EL737__BAD_ID");
|
|
break;
|
|
case -5:
|
|
strcpy(pBuffer, "EL737__BAD_ILLG");
|
|
break;
|
|
case -2:
|
|
strcpy(pBuffer, "EL737__BAD_LOC");
|
|
break;
|
|
case -11:
|
|
strcpy(pBuffer, "EL737__BAD_MALLOC");
|
|
break;
|
|
case -21:
|
|
strcpy(pBuffer, "EL737__BAD_NOT_BCD");
|
|
break;
|
|
case -4:
|
|
strcpy(pBuffer, "EL737__BAD_OFL");
|
|
break;
|
|
case -29:
|
|
strcpy(pBuffer, "EL737__BAD_PAR");
|
|
break;
|
|
|
|
case -17:
|
|
strcpy(pBuffer, "EL737__BAD_RECV");
|
|
break;
|
|
case -19:
|
|
strcpy(pBuffer, "EL737__BAD_RECV_NET");
|
|
break;
|
|
case -18:
|
|
strcpy(pBuffer, "EL737__BAD_RECV_PIPE");
|
|
break;
|
|
case -20:
|
|
strcpy(pBuffer, "EL737__BAD_RECV_UNKN");
|
|
break;
|
|
case -22:
|
|
strcpy(pBuffer, "EL737__BAD_RECVLEN");
|
|
break;
|
|
case -24:
|
|
strcpy(pBuffer, "EL737__BAD_RECV1");
|
|
break;
|
|
case -26:
|
|
strcpy(pBuffer, "EL737__BAD_RECV1_NET");
|
|
break;
|
|
case -25:
|
|
strcpy(pBuffer, "EL737__BAD_RECV1_PIPE");
|
|
break;
|
|
case -27:
|
|
strcpy(pBuffer, "EL737__BAD_RNG");
|
|
break;
|
|
case -13:
|
|
strcpy(pBuffer, "EL737__BAD_SEND");
|
|
break;
|
|
case -14:
|
|
strcpy(pBuffer, "EL737__BAD_SEND_PIPE");
|
|
break;
|
|
case -15:
|
|
strcpy(pBuffer, "EL737__BAD_SEND_NET");
|
|
break;
|
|
case -16:
|
|
strcpy(pBuffer, "EL737__BAD_SEND_UNKN");
|
|
break;
|
|
case -12:
|
|
strcpy(pBuffer, "EL737__BAD_SENDLEN");
|
|
break;
|
|
case -7:
|
|
strcpy(pBuffer, "EL737__BAD_SOCKET");
|
|
break;
|
|
case -1:
|
|
strcpy(pBuffer, "EL737__BAD_TMO");
|
|
break;
|
|
default:
|
|
strcpy(pBuffer, "Unknown EL737 error");
|
|
break;
|
|
}
|
|
}
|