- Removed old code

- Extended tasker to support task groups
- Added task functions for motors and counters
- Modifed devexec to use the new task functions
- Modified TAS to treat the monochromator separatly
- Coded a EIGER monochromator module to reflect even more new
  requirements
- Added EPICS counters and motors
- Modified multicounter to be better performing
This commit is contained in:
koennecke
2013-04-02 15:13:36 +00:00
parent 59d292cb79
commit 966f8e30a8
22 changed files with 754 additions and 9947 deletions

367
A1931.c
View File

@ -1,367 +0,0 @@
/*-------------------------------------------------------------------------
This is the implementation file for a driver for the Risoe A1931a
temperature controller. This driver controls the device through a GPIB
interface.
copyright: see file COPYRIGHT
Mark Koennecke, February 2003
-------------------------------------------------------------------------*/
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <assert.h>
#include <unistd.h>
#include <fortify.h>
#include <sics.h>
#include <obpar.h>
#include <evcontroller.h>
#include <evcontroller.i>
#include <evdriver.i>
#include <gpibcontroller.h>
#include "A1931.h"
/*========================== private data structure ====================*/
typedef struct {
int sensor; /* the control sensor */
pGPIB gpib; /* the GPIB interface to use in order to talk to the thing */
int gpibAddress; /* address on bus */
int devID; /* deviceID of the controller on the GPIB */
char errorBuffer[132]; /* a buffer for error messages from the thing */
char commandLine[132]; /* buffer to keep the offending command line */
int errorCode; /* error indicator */
} A1931, *pA1931;
/*============================ defines ================================*/
#define COMMERROR -300
#define A1931ERROR -301
#define FILEERROR -302
/*====================================================================*/
static char *A1931comm(pEVDriver pData, char *command)
{
char buffer[256], *pPtr;
int status;
pA1931 self = NULL;
Tcl_DString reply;
self = (pA1931) pData->pPrivate;
assert(self);
/*
send
*/
strlcpy(buffer, command, 250);
strcat(buffer, "\n");
status = GPIBsend(self->gpib, self->devID, buffer, (int) strlen(buffer));
if (status < 0) {
self->errorCode = COMMERROR;
GPIBerrorDescription(self->gpib, status, self->errorBuffer, 131);
return NULL;
}
/*
read until > is found
*/
Tcl_DStringInit(&reply);
while (1) {
pPtr = GPIBreadTillTerm(self->gpib, self->devID, 10);
if (strstr(pPtr, "GPIB READ ERROR") != NULL) {
free(pPtr);
self->errorCode = COMMERROR;
Tcl_DStringFree(&reply);
return NULL;
} else {
Tcl_DStringAppend(&reply, pPtr, -1);
if (strchr(pPtr, '>') != NULL) {
/*
finished
*/
free(pPtr);
break;
}
free(pPtr);
}
}
pPtr = NULL;
pPtr = strdup(Tcl_DStringValue(&reply));
Tcl_DStringFree(&reply);
if (pPtr[0] == '#') {
/*
error
*/
self->errorCode = A1931ERROR;
strlcpy(self->errorBuffer, pPtr, 131);
free(pPtr);
return NULL;
}
return pPtr;
}
/*--------------------------------------------------------------------*/
static int A1931command(pEVDriver pData, char *command, char *replyBuffer,
int replyBufferLen)
{
pA1931 self = NULL;
char *pReply = NULL;
self = (pA1931) pData->pPrivate;
assert(self);
pReply = A1931comm(pData, command);
if (pReply != NULL) {
strlcpy(replyBuffer, pReply, replyBufferLen);
free(pReply);
return 1;
} else {
strlcpy(replyBuffer, self->errorBuffer, replyBufferLen);
return 0;
}
}
/*====================================================================*/
static int A1931Init(pEVDriver pData)
{
pA1931 self = NULL;
self = (pA1931) pData->pPrivate;
assert(self);
self->devID = GPIBattach(self->gpib, 0, self->gpibAddress, 0, 13, 0, 0);
if (self->devID < 0) {
return 0;
}
return 1;
}
/*====================================================================*/
static int A1931Close(pEVDriver pData)
{
pA1931 self = NULL;
self = (pA1931) pData->pPrivate;
assert(self);
GPIBdetach(self->gpib, self->devID);
self->devID = 0;
return 1;
}
/*===================================================================*/
static int A1931Get(pEVDriver pData, float *fPos)
{
pA1931 self = NULL;
char buffer[132], command[50];
int status;
self = (pA1931) pData->pPrivate;
assert(self);
sprintf(command, "?TEMP%1.1d", self->sensor);
status = A1931command(pData, command, buffer, 131);
if (!status) {
return 0;
}
sscanf(buffer, "%f", fPos);
return 1;
}
/*=====================================================================*/
static int A1931Set(pEVDriver pData, float fNew)
{
pA1931 self = NULL;
char buffer[132], command[50];
int status;
self = (pA1931) pData->pPrivate;
assert(self);
sprintf(command, "SET%1.1d=%f", self->sensor, fNew);
status = A1931command(pData, command, buffer, 131);
if (!status) {
return 0;
}
return 1;
}
/*====================================================================*/
static int A1931error(pEVDriver pData, int *iCode, char *errBuff,
int bufLen)
{
pA1931 self = NULL;
char pError[256];
self = (pA1931) pData->pPrivate;
assert(self);
*iCode = self->errorCode;
sprintf(pError, "ERROR: %s", self->errorBuffer);
strlcpy(errBuff, pError, bufLen);
return 1;
}
/*====================================================================*/
static int A1931fix(pEVDriver pData, int iCode)
{
pA1931 self = NULL;
char pError[256];
self = (pA1931) pData->pPrivate;
assert(self);
if (iCode == COMMERROR) {
GPIBclear(self->gpib, self->devID);
return DEVREDO;
}
return DEVFAULT;
}
/*=====================================================================*/
pEVDriver CreateA1931Driver(int argc, char *argv[])
{
pEVDriver self = NULL;
pA1931 priv = NULL;
if (argc < 2) {
return NULL;
}
/*
allocate space
*/
self = CreateEVDriver(argc, argv);
priv = (pA1931) malloc(sizeof(A1931));
if (self == NULL || priv == NULL) {
return NULL;
}
memset(priv, 0, sizeof(A1931));
self->pPrivate = priv;
self->KillPrivate = free;
/*
initialize
*/
priv->gpib = (pGPIB) FindCommandData(pServ->pSics, argv[0], "GPIB");
if (!priv->gpib) {
DeleteEVDriver(self);
return NULL;
}
priv->sensor = 1;
priv->gpibAddress = atoi(argv[1]);
/*
initialize function pointers
*/
self->Send = A1931command;
self->Init = A1931Init;
self->Close = A1931Close;
self->GetValue = A1931Get;
self->SetValue = A1931Set;
self->GetError = A1931error;
self->TryFixIt = A1931fix;
return self;
}
/*=======================================================================*/
static int downloadFile(pA1931 self, FILE * fd)
{
char buffer[132], *pPtr;
int status;
while (1) {
if (fgets(buffer, 130, fd) == NULL) {
self->errorCode = FILEERROR;
strcpy(self->errorBuffer, "Failed to read from file");
return 0;
}
if (strstr(buffer, "$END") != NULL) {
break;
}
status =
GPIBsend(self->gpib, self->devID, buffer, (int) strlen(buffer));
if (status < 0) {
self->errorCode = COMMERROR;
GPIBerrorDescription(self->gpib, status, self->errorBuffer, 131);
return 0;
}
pPtr = GPIBreadTillTerm(self->gpib, self->devID, 10);
if (pPtr[0] == '#') {
self->errorCode = A1931ERROR;
strlcpy(self->errorBuffer, pPtr, 131);
strlcpy(self->commandLine, buffer, 131);
free(pPtr);
return 0;
}
free(pPtr);
usleep(50);
}
return 1;
}
/*=======================================================================*/
int A1931Action(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
pEVControl pEV = NULL;
pA1931 self = NULL;
char buffer[256];
char error[132];
FILE *fd = NULL;
int status, iCode;
pEV = (pEVControl) pData;
assert(pEV);
self = (pA1931) pEV->pDriv->pPrivate;
assert(self);
if (argc > 1) {
strtolower(argv[1]);
if (strcmp(argv[1], "sensor") == 0) {
if (argc > 2) {
/* set case */
if (!SCMatchRights(pCon, usUser)) {
return 0;
}
self->sensor = atoi(argv[2]);
SCSendOK(pCon);
return 1;
} else {
/* get case */
sprintf(buffer, "%s.sensor = %d", argv[0], self->sensor);
SCWrite(pCon, buffer, eValue);
return 1;
}
} else if (strcmp(argv[1], "list") == 0) {
sprintf(buffer, "%s.sensor = %d", argv[0], self->sensor);
SCWrite(pCon, buffer, eValue);
return EVControlWrapper(pCon, pSics, pData, argc, argv);
} else if (strcmp(argv[1], "file") == 0) {
if (!SCMatchRights(pCon, usUser)) {
return 0;
}
if (argc < 3) {
SCWrite(pCon, "ERROR: need filename argument", eError);
return 0;
}
fd = fopen(argv[2], "r");
if (fd == NULL) {
sprintf(buffer, "ERROR: failed to open %s", argv[2]);
SCWrite(pCon, buffer, eError);
return 0;
}
status = downloadFile(self, fd);
fclose(fd);
if (!status) {
A1931error(pEV->pDriv, &iCode, error, 131);
sprintf(buffer, "%s while transfering file", error);
SCWrite(pCon, buffer, eError);
sprintf(buffer, "Offending command: %s", self->commandLine);
SCWrite(pCon, buffer, eError);
return 0;
}
SCSendOK(pCon);
return 1;
}
}
return EVControlWrapper(pCon, pSics, pData, argc, argv);
}

20
A1931.h
View File

@ -1,20 +0,0 @@
/*-------------------------------------------------------------------------
This is the header file for a driver for the Risoe A1931a temperature
controller. This driver controls the device through a GPIB interface.
copyright: see file COPYRIGHT
Mark Koennecke, February 2003
-------------------------------------------------------------------------*/
#ifndef A1931A
#define A19131A
#include "sics.h"
pEVDriver CreateA1931Driver(int argc, char *argv[]);
int A1931Action(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[]);
#endif

View File

@ -1,626 +0,0 @@
/*
* -*- linux-c -*-
* Linux Kernel Module for the Audine Camera
* Copyright (C) 2001 Peter Kirchgessner
* http://www.kirchgessner.net, mailto:peter@kirchgessner.net
*
* Modified by F. Manenti <oss_astr_cav@arcanet.it> for the use in the
* NOVA environment (nova.sourceforge.net)
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The sample interface routines for the module have been taken from the
* Linux Kernel Module Programming Guide by Ori Pomerantz contained
* in the Linux Documentation Project.
*
*/
#include "audineccd.h"
#include "audinelib.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/ioctl.h>
#include <errno.h>
#define AUD_DEVICE_FILE "/dev/audine"
#define ERRNORET(a) return (errno = a, -(a))
#define AUD_HANDLE_CHECK(a) \
{ if (!(a)) ERRNORET (EINVAL); if ((a)->fd < 0) ERRNORET (EBADF); }
struct aud_handle_s {
int fd;
int single_read;
};
AUD_HANDLE aud_open(void)
{
AUD_HANDLE aud = (AUD_HANDLE) calloc(1, sizeof(struct aud_handle_s));
if (!aud)
return 0;
aud->fd = open(AUD_DEVICE_FILE, O_RDWR);
if (aud->fd < 0) {
free(aud);
return 0;
}
aud->single_read = 1;
return aud;
}
void aud_close(AUD_HANDLE aud)
{
if (aud) {
if (aud->fd >= 0)
close(aud->fd);
free(aud);
}
}
char *aud_version(const AUD_HANDLE aud)
{
static struct ccd_capability Info;
char *version = "";
int ret;
if (aud) {
ret = ioctl(aud->fd, CCD_RD_VER, &Info);
if (ret == 0)
version = &(Info.name[0]);
}
return version;
}
int aud_clear(const AUD_HANDLE aud, int nclear)
{
int ret = 0;
if (nclear > 0)
ret = ioctl(aud->fd, CCD_CLR, &nclear);
return ret;
}
int aud_binning_set(const AUD_HANDLE aud, int vb, int hb)
{
struct ccd_capability Info;
AUD_HANDLE_CHECK(aud);
if ((vb < 1) || (vb > 4) || (hb < 1) || (hb > 4))
ERRNORET(EINVAL);
Info.width = vb;
Info.height = hb;
return ioctl(aud->fd, CCD_SET_BNN, &Info);
}
int aud_binning_get(const AUD_HANDLE aud, int *vb, int *hb)
{
struct ccd_capability Info;
int ret;
AUD_HANDLE_CHECK(aud);
Info.width = 0;
Info.height = 0;
ret = ioctl(aud->fd, CCD_SET_BNN, &Info);
if (ret != 0)
return ret;
if (vb)
*vb = Info.width;
if (hb)
*hb = Info.height;
return 0;
}
int aud_geometry_set(const AUD_HANDLE aud, int x, int y, int width,
int height)
{
struct ccd_capability Info;
AUD_HANDLE_CHECK(aud);
Info.minwidth = x;
Info.minheight = y;
Info.width = width;
Info.height = height;
return ioctl(aud->fd, CCD_SET_WND, &Info);
}
int aud_geometry_reset(const AUD_HANDLE aud)
{
AUD_HANDLE_CHECK(aud);
return ioctl(aud->fd, CCD_RST_WND);
}
int aud_geometry_get(const AUD_HANDLE aud, int *xorigin, int *yorigin,
int *winwidth, int *winheight, int *color)
{
struct ccd_capability Info;
int ret;
AUD_HANDLE_CHECK(aud);
ret = ioctl(aud->fd, CCD_RD_GEOM, &Info);
if (ret != 0)
return ret;
if (xorigin)
*xorigin = Info.minwidth;
if (yorigin)
*yorigin = Info.minheight;
if (winwidth)
*winwidth = Info.width;
if (winheight)
*winheight = Info.height;
if (color)
*color = Info.color;
return 0;
}
int aud_port_set(const AUD_HANDLE aud, int base)
{
AUD_HANDLE_CHECK(aud);
if (base <= 0)
return -EINVAL;
return ioctl(aud->fd, CCD_SET_PRT, &base);
}
int aud_port_get(const AUD_HANDLE aud, int *base)
{
AUD_HANDLE_CHECK(aud);
if (!base)
return -1;
*base = 0;
return ioctl(aud->fd, CCD_SET_PRT, base);
}
static int aud_line_ctrl_set(const AUD_HANDLE aud, int cmd, int ctrl)
{
AUD_HANDLE_CHECK(aud);
if ((ctrl != 1) && (ctrl != 2) && (ctrl != 4) && (ctrl != 8))
ERRNORET(EINVAL);
return ioctl(aud->fd, cmd, &ctrl);
}
static int aud_line_set(const AUD_HANDLE aud, int cmd, int on_off)
{
AUD_HANDLE_CHECK(aud);
if (on_off != 0)
on_off = 1;
return ioctl(aud->fd, cmd, &on_off);
}
int aud_amplifier_ctrl_set(const AUD_HANDLE aud, int ctrl)
{
return aud_line_ctrl_set(aud, CCD_SET_AMP, ctrl);
}
int aud_amplifier_set(const AUD_HANDLE aud, int on_off)
{
return aud_line_set(aud, CCD_SWTC_AMP, on_off);
}
int aud_shutter_ctrl_set(const AUD_HANDLE aud, int ctrl)
{
return aud_line_ctrl_set(aud, CCD_SET_SHT, ctrl);
}
int aud_shutter_set(const AUD_HANDLE aud, int on_off)
{
return aud_line_set(aud, CCD_SWTC_SHT, on_off);
}
int aud_aux0_ctrl_set(const AUD_HANDLE aud, int ctrl)
{
return aud_line_ctrl_set(aud, CCD_SET_AX0, ctrl);
}
int aud_aux0_set(const AUD_HANDLE aud, int on_off)
{
return aud_line_set(aud, CCD_SWTC_AX0, on_off);
}
int aud_aux1_ctrl_set(const AUD_HANDLE aud, int ctrl)
{
return aud_line_ctrl_set(aud, CCD_SET_AX1, ctrl);
}
int aud_aux1_set(const AUD_HANDLE aud, int on_off)
{
return aud_line_set(aud, CCD_SWTC_AX1, on_off);
}
int aud_ccd_info_get(const AUD_HANDLE aud, char **name, int *width,
int *height, int *color)
{
static struct ccd_capability Info;
int ret;
AUD_HANDLE_CHECK(aud);
if ((ret = ioctl(aud->fd, CCD_RD_CHIP, &Info)) != 0)
return ret;
if (name)
*name = Info.name;
if (width)
*width = Info.width;
if (height)
*height = Info.height;
if (color)
*color = Info.color;
return 0;
}
int aud_ccd_listentry_get(const AUD_HANDLE aud, int entry, char **name,
int *width, int *height, int *color)
{
static struct ccd_capability Info;
int ret;
AUD_HANDLE_CHECK(aud);
Info.color = entry;
if ((ret = ioctl(aud->fd, CCD_RD_CCDL, &Info)) != 0)
return ret;
if (name)
*name = Info.name;
if (width)
*width = Info.width;
if (height)
*height = Info.height;
if (color)
*color = Info.color;
return 0;
}
void aud_single_read_set(AUD_HANDLE aud, int single_read)
{
if (aud)
aud->single_read = single_read;
}
int aud_image_read(const AUD_HANDLE aud, char **buf, int *bufsize,
int *width, int *height, int *color)
{
int ret;
int nbytes, nread, len;
char *imgbuf;
AUD_HANDLE_CHECK(aud);
if ((!buf) || (!bufsize))
ERRNORET(EINVAL);
if ((!width) || (!height) || (!color))
ERRNORET(EINVAL);
if ((ret = aud_geometry_get(aud, 0, 0, width, height, color)) != 0)
return ret;
/* We get 2 bytes per pixel */
nbytes = *width * *height * 2;
/* Do we have to free the user buffer ? */
if ((*bufsize < nbytes) && (*buf)) {
free(*buf);
*buf = 0;
*bufsize = 0;
}
/* If buffer not supplied, allocate buffer */
if (!(*buf)) {
*buf = malloc(nbytes);
if (!*buf)
ERRNORET(ENOMEM);
*bufsize = nbytes;
}
/* Start reading image */
if ((ret = ioctl(aud->fd, CCD_RD_IMG)) != 0)
return ret;
imgbuf = *buf;
while (nbytes > 0) {
if (aud->single_read) {
nread = nbytes;
} else {
nread = *width * 2;
if (nread > nbytes)
nread = nbytes;
}
len = read(aud->fd, imgbuf, nread);
if (len <= 0)
return -1;
nbytes -= len;
imgbuf += len;
}
return 0;
}
static void aud_ccdstruct_log(const char *fct, int ret,
const struct ccd_capability *info)
{
printf("\nFunction %s returned %d\n", fct, ret);
if (ret != 0)
return;
printf("Name : %-32s\n", info->name);
printf
("Width: %-6d Height: %-6d Minwidth: %-6d Minheight: %-6d Color: %d\n",
info->width, info->height, info->minwidth, info->minheight,
info->color);
}
void aud_ioctl_test(AUD_HANDLE aud)
{
int ret;
struct ccd_capability info;
char *buf = 0, *name;
int bufsize = 0, width, height, color;
int j;
if ((!aud) || (aud->fd < 0))
return;
/* Read driver version */
ret = ioctl(aud->fd, CCD_RD_VER, &info);
aud_ccdstruct_log("CCD_RD_VER", ret, &info);
/* Read chip information */
ret = ioctl(aud->fd, CCD_RD_CHIP, &info);
aud_ccdstruct_log("CCD_RD_CHIP", ret, &info);
/* Read geometry */
ret = ioctl(aud->fd, CCD_RD_GEOM, &info);
aud_ccdstruct_log("CCD_RD_GEOM", ret, &info);
/* Set Window */
info.minwidth = 1;
info.minheight = 2;
info.width = 200;
info.height = 100;
ret = ioctl(aud->fd, CCD_SET_WND, &info);
printf("\nCalled CCD_SET_WND: (1,2) (200,100)\n");
/* Read geometry */
ret = ioctl(aud->fd, CCD_RD_GEOM, &info);
aud_ccdstruct_log("CCD_RD_GEOM", ret, &info);
/* Set binning */
info.width = 2;
info.height = 3;
printf("\nSet binning %dx%d", info.width, info.height);
ret = ioctl(aud->fd, CCD_SET_BNN, &info);
aud_ccdstruct_log("CCD_SET_BNN", ret, &info);
/* Read geometry */
ret = ioctl(aud->fd, CCD_RD_GEOM, &info);
aud_ccdstruct_log("CCD_RD_GEOM", ret, &info);
/* (Re-)Set binning */
info.width = 1;
info.height = 1;
printf("\nSet binning %dx%d", info.width, info.height);
ret = ioctl(aud->fd, CCD_SET_BNN, &info);
aud_ccdstruct_log("CCD_SET_BNN", ret, &info);
/* Read geometry */
ret = ioctl(aud->fd, CCD_RD_GEOM, &info);
aud_ccdstruct_log("CCD_RD_GEOM", ret, &info);
/* Clear two times */
info.width = 2;
printf("\nStart clear %d times\n", info.width);
fflush(stdout);
ret = ioctl(aud->fd, CCD_CLR, &info.width);
printf("Clear finished.\n");
/* Reading */
printf("Start reading image\n");
ret = aud_image_read(aud, &buf, &bufsize, &width, &height, &color);
printf
("Finished reading: ret=%d width=%d height=%d color=%d bufsize=%d\n",
ret, width, height, color, bufsize);
/* Set binning */
info.width = 2;
info.height = 3;
printf("\nSet binning %dx%d", info.width, info.height);
ret = ioctl(aud->fd, CCD_SET_BNN, &info);
aud_ccdstruct_log("CCD_SET_BNN", ret, &info);
/* Reading */
printf("Start reading small image\n");
ret = aud_image_read(aud, &buf, &bufsize, &width, &height, &color);
printf
("Finished reading: ret=%d width=%d height=%d color=%d bufsize=%d\n",
ret, width, height, color, bufsize);
/* Reset window */
ret = ioctl(aud->fd, CCD_RST_WND);
printf("\nReset window\n");
/* Reset binning */
info.width = 1;
info.height = 1;
printf("\nSet binning %dx%d", info.width, info.height);
ret = ioctl(aud->fd, CCD_SET_BNN, &info);
aud_ccdstruct_log("CCD_SET_BNN", ret, &info);
/* Read geometry */
ret = ioctl(aud->fd, CCD_RD_GEOM, &info);
aud_ccdstruct_log("CCD_RD_GEOM", ret, &info);
/* Reading */
printf("Start reading large image\n");
ret = aud_image_read(aud, &buf, &bufsize, &width, &height, &color);
printf
("Finished reading: ret=%d width=%d height=%d color=%d bufsize=%d\n",
ret, width, height, color, bufsize);
/* Read current port */
ret = aud_port_get(aud, &j);
printf("\naud_port_get returned with %d. Port=0x%x\n", ret, j);
printf("\nList of supported CCDs:\n");
j = 0;
while (aud_ccd_listentry_get(aud, j, &name, &info.width, &info.height,
&info.color) == 0) {
printf("%d: %s, %dx%d, %d\n", j, name, info.width, info.height,
info.color);
j++;
}
}
#define FITS_WRITE_BOOLCARD(fp,key,value) \
{char card[81]; \
sprintf (card, "%-8.8s= %20s%50s", key, value ? "T" : "F", " "); \
fwrite (card, 1, 80, fp); }
#define FITS_WRITE_LONGCARD(fp,key,value) \
{char card[81]; \
sprintf (card, "%-8.8s= %20ld%50s", key, (long)value, " "); \
fwrite (card, 1, 80, fp); }
#define FITS_WRITE_DOUBLECARD(fp,key,value) \
{char card[81], dbl[21], *istr; \
sprintf (dbl, "%20f", (double)value); istr = strstr (dbl, "e"); \
if (istr) *istr = 'E'; \
sprintf (card, "%-8.8s= %20.20s%50s", key, dbl, " "); \
fwrite (card, 1, 80, fp); }
#define FITS_WRITE_STRINGCARD(fp,key,value) \
{char card[81]; int k;\
sprintf (card, "%-8.8s= \'%s", key, value); \
for (k = strlen (card); k < 81; k++) card[k] = ' '; \
k = strlen (key); if (k < 8) card[19] = '\''; else card[11+k] = '\''; \
fwrite (card, 1, 80, fp); }
#define FITS_WRITE_CARD(fp,value) \
{char card[81]; \
sprintf (card, "%-80.80s", value); \
fwrite (card, 1, 80, fp); }
int audine_fits_write(const char *fname, const char *img,
int width, int height)
{
FILE *fp;
char value[50];
unsigned short *us_img = (unsigned short *) img;
unsigned short *row;
int x, y, high, low;
long pos;
time_t timp;
fp = fopen(fname, "w");
if (fp) {
FITS_WRITE_BOOLCARD(fp, "SIMPLE", 1);
FITS_WRITE_LONGCARD(fp, "BITPIX", 16);
FITS_WRITE_LONGCARD(fp, "NAXIS", 2);
FITS_WRITE_LONGCARD(fp, "NAXIS1", width);
FITS_WRITE_LONGCARD(fp, "NAXIS2", height);
FITS_WRITE_DOUBLECARD(fp, "BZERO", 0.0);
FITS_WRITE_DOUBLECARD(fp, "BSCALE", 1.0);
FITS_WRITE_DOUBLECARD(fp, "DATAMIN", 0.0);
FITS_WRITE_DOUBLECARD(fp, "DATAMAX", 32767.0);
FITS_WRITE_CARD(fp, " ");
FITS_WRITE_CARD(fp, "HISTORY THIS FILE WAS GENERATED BY AUDINELIB");
FITS_WRITE_CARD(fp, " ");
timp = time(NULL);
strftime(value, sizeof(value), "%d/%m/%Y", gmtime(&timp));
FITS_WRITE_STRINGCARD(fp, "DATE", value);
FITS_WRITE_CARD(fp, "END");
/* Fill up primary HDU to multiple of 2880 bytes */
fflush(fp);
pos = ftell(fp) % 2880;
if (pos != 0) {
pos = 2880 - pos;
while (pos-- > 0)
putc(' ', fp);
}
/* FITS standard requires integer data to be most significant
byte first, */
/* image origin bottom left. We want to create an astronomical
oriented image (top is bottom, left is right) */
for (y = 0; y < height; y++) {
row = us_img + y * width;
for (x = width - 1; x >= 0; x--) {
high = (row[x] >> 8) & 0xff;
low = (row[x] & 0xff);
putc(high, fp);
putc(low, fp);
}
}
/* Fill up file to multiple of 2880 bytes */
fflush(fp);
pos = ftell(fp) % 2880;
if (pos != 0) {
pos = 2880 - pos;
while (pos-- > 0)
putc(0, fp);
}
fclose(fp);
} else {
return -1;
}
return 0;
}

View File

@ -1,79 +0,0 @@
/*
* -*- linux-c -*-
* Library Module for the Audine Camera
* Copyright (C) 2001 Peter Kirchgessner
* http://www.kirchgessner.net, mailto:peter@kirchgessner.net
*
* Modified by F. Manenti <oss_astr_cav@arcanet.it> for the use in the
* NOVA environment (nova.sourceforge.net)
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The sample interface routines for the module have been taken from the
* Linux Kernel Module Programming Guide by Ori Pomerantz contained
* in the Linux Documentation Project.
*
*/
#ifndef _AUDINELIB_H_
#define _AUDINELIB_H_
typedef struct aud_handle_s *AUD_HANDLE;
AUD_HANDLE aud_open(void);
void aud_close(AUD_HANDLE aud);
char *aud_version(const AUD_HANDLE aud);
int aud_image_read(const AUD_HANDLE aud, char **buf, int *bufsize,
int *width, int *height, int *color);
void aud_single_read_set(AUD_HANDLE aud, int single_read);
int aud_ccd_info_get(const AUD_HANDLE aud, char **name,
int *width, int *height, int *color);
int aud_ccd_listentry_get(const AUD_HANDLE aud, int entry, char **name,
int *width, int *height, int *color);
int aud_binning_set(const AUD_HANDLE aud, int vb, int hb);
int aud_binning_get(const AUD_HANDLE aud, int *vb, int *hb);
int aud_geometry_set(const AUD_HANDLE aud, int x, int y, int width,
int height);
int aud_geometry_get(const AUD_HANDLE aud, int *xorigin, int *yorigin,
int *winwidth, int *winheight, int *color);
int aud_geometry_reset(const AUD_HANDLE aud);
int aud_amplifier_ctrl_set(const AUD_HANDLE aud, int ctrl);
int aud_amplifier_set(const AUD_HANDLE aud, int off_on);
int aud_shutter_ctrl_set(const AUD_HANDLE aud, int ctrl);
int aud_shutter_set(const AUD_HANDLE aud, int off_on);
int aud_aux0_ctrl_set(const AUD_HANDLE aud, int ctrl);
int aud_aux0_set(const AUD_HANDLE aud, int off_on);
int aud_aux1_ctrl_set(const AUD_HANDLE aud, int ctrl);
int aud_aux1_set(const AUD_HANDLE aud, int off_on);
int aud_clear(const AUD_HANDLE, int nclear);
void aud_ioctl_test(AUD_HANDLE aud);
int audine_fits_write(const char *fname, const char *img,
int width, int height);
#endif

698
docho.c
View File

@ -1,698 +0,0 @@
/*--------------------------------------------------------------------------
D o C h o
A SICS driver for a Dornier Chopper Control System accessed through a
RS-232 interface connected to a Macintosh PC running the SerialPortServer
terminal server program. There are two choppers which ususally run at fixed
speed ratios against each other. There ia also a phase difference between
the two choppers. And lots of machine surveillance parameters.
This driver is used by the generic chopper or device controller as described
in choco.tex.
Mark Koennecke, January 1999
Modified to support a single chopper only,
Uwe Filges, Mark Koennecke; November 2001
--------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <fortify.h>
#include <sics.h>
#include <stringdict.h>
#include "hardsup/serialsinq.h"
#include "hardsup/el734_errcodes.h"
#include "hardsup/el734fix.h"
#include <codri.h>
/*-----------------------------------------------------------------------
A private data structure for this Dornier chopper
-------------------------------------------------------------------------*/
typedef struct {
char *pHost;
int iPort;
int iChannel;
void *pData;
int iRefreshIntervall;
pStringDict pPar;
time_t tRefresh;
int iStop;
long lTask;
int iError;
int iBusy;
float fRatio;
int iSingle;
char pError[80];
} DoCho, *pDoCho;
/*
pHost, iPort and iChannel combined are the adress of the chopper
controller at the Macintosh terminal server. pData is the serial
port connection data structure needed and managed by the SerialIO
functions.
As the communication with the Dornier Chopper System is very slow the
parameter list of this driver will only be updated a predefined time
intervalls. In between buffered values will be returned for requests.
The buffered parameters are held in the string dictioanry pPar.
iRefreshIntervall is the time between refreshs. tRefresh is the time for
the next refresh. iBusy is flag which indicates, that it was tried to
modify a variable. This will only be reflected with the next status update.
In between DoChoCheckPar might conclude, that the chopper is already
done. iBusy is meant to stop that. It is set when a parameter is changed
and cleared bu the status message code. DoChoCheckPar checks for it.
Refreshing will be performed by a special SICS task which will be
started when the driver is initialized. In order to stop this task when
need arises the parameter iStop can be set to true.
iError is the last error reported on this device. If no error: 0
fRatio is the target value for the chopper ratio. In contrast to the
other parameters, its target value cannot be extracted from the chopper
status message.
iSingle is a flag which is true if only a single chopper is controlled
through this driver. This supports the POLDI single choper case.
*/
/*----------------------------------------------------------------------
ERROR CODES:
*/
#define UNDRIVABLE -8002
#define UNKNOWNPAR -8003
#define PARERROR -8004
#define BADSYNC -8005
#define BADSTOP -8006
#define CHOPERROR -8007
extern char *trim(char *pTrim); /* trim.c */
/*----------------------------------------------------------------------*/
static void SplitChopperReply(pCodri self, char *prefix, char *pBueffel)
{
char pToken[30], pValue[20], pEntry[80];
char *pPtr, *pTok, *pVal;
int iCount, iRet;
pDoCho pPriv = NULL;
pPriv = (pDoCho) self->pPrivate;
/* decompose pBueffel and store into string dictionary */
pPtr = strtok(pBueffel, ";");
while (pPtr != NULL) {
iCount = sscanf(pPtr, "%s %s", pToken, pValue);
if (iCount == 2) {
pTok = trim(pToken);
pVal = trim(pValue);
pEntry[0] = '\0';
sprintf(pEntry, "%s.%s", prefix, pTok);
iRet = StringDictUpdate(pPriv->pPar, pEntry, pVal);
if (!iRet) {
StringDictAddPair(pPriv->pPar, pEntry, pVal);
strcat(self->pParList, pEntry);
strcat(self->pParList, ",");
}
} else {
/* this fixes a bug with oversized messages in dphas oder averl*/
if (strstr(pPtr, "dphas") != NULL ) {
sprintf(pEntry, "%s.dphas", prefix);
iRet = StringDictUpdate(pPriv->pPar, pEntry, pPtr + 5);
if (!iRet) {
StringDictAddPair(pPriv->pPar, pEntry, pPtr + 5);
strcat(self->pParList, pEntry);
strcat(self->pParList, ",");
}
}
if (strstr(pPtr, "averl") != NULL ) {
sprintf(pEntry, "%s.averl", prefix);
iRet = StringDictUpdate(pPriv->pPar, pEntry, pPtr + 5);
if (!iRet) {
StringDictAddPair(pPriv->pPar, pEntry, pPtr + 5);
strcat(self->pParList, pEntry);
strcat(self->pParList, ",");
}
}
}
pPtr = strtok(NULL, ";");
}
}
/*-------------------------------------------------------------------------
Well, DoChoStatus sends a status request to the Dornier chopper control
system. There is a gotcha, you need three reads to get the full information.
Then the answer is parsed and decomposed into parameter content for the
string dictionary. The single status components are separated by ;.
-------------------------------------------------------------------------*/
static int DoChoStatus(pCodri self)
{
int iRet, iCount, iCode;
char pBueffel[1024], pToken[30], pValue[20];
char *pPtr, *pTok, *pVal;
pDoCho pPriv = NULL;
assert(self);
pPriv = (pDoCho) self->pPrivate;
assert(pPriv);
pPriv->iBusy = 0;
pPriv->iError = 0;
/* first send, command, returns the echo */
iRet = SerialWriteRead(&(pPriv->pData), "asyst 1", pBueffel, 1023);
if (iRet < 0) {
pPriv->iError = iRet;
return 0;
}
/* next send: reads first chopper line */
iRet = SerialWriteRead(&(pPriv->pData), "", pBueffel, 1023);
if (iRet < 0) {
pPriv->iError = iRet;
return 0;
}
SplitChopperReply(self, "chopper1", pBueffel);
if (!pPriv->iSingle) {
/* second send: get next second chopper line */
iRet = SerialWriteRead(&(pPriv->pData), "", pBueffel, 1023);
if (iRet < 0) {
pPriv->iError = iRet;
return 0;
}
SplitChopperReply(self, "chopper2", pBueffel);
}
return 1;
}
/*-------------------------------------------------------------------------*/
static int DoChoTask(void *pData)
{
pCodri self = NULL;
pDoCho pPriv = NULL;
int iCode, iRet;
char pDummy[60];
self = (pCodri) pData;
assert(self);
pPriv = (pDoCho) self->pPrivate;
assert(pPriv);
/* check for stop */
if (pPriv->iStop)
return 0;
/* check if it is time to run a status request */
if (time(NULL) > pPriv->tRefresh) {
/* try, fix error */
if (pPriv->iError != 0) {
self->GetError(self, &iCode, pDummy, 59);
iRet = self->TryFixIt(self, iCode);
if (iRet == CHFAIL) {
pPriv->tRefresh = time(NULL) + pPriv->iRefreshIntervall;
return 1;
}
}
/* do it */
DoChoStatus(self);
pPriv->tRefresh = time(NULL) + pPriv->iRefreshIntervall;
}
return 1;
}
/*------------------------------------------------------------------------*/
static void DoChoKill(void *pData)
{
pCodri self = NULL;
pDoCho pPriv = NULL;
self = (pCodri) pData;
if (!self)
return;
pPriv = (pDoCho) self->pPrivate;
if (!pPriv)
return;
if (pPriv->pData) {
SerialClose(&(pPriv->pData));
pPriv->pData = NULL;
}
if (pPriv->pHost)
free(pPriv->pHost);
if (pPriv->pPar)
DeleteStringDict(pPriv->pPar);
free(pPriv);
}
/*-------------------------------------------------------------------------*/
static int DoChoInit(pCodri self)
{
pDoCho pPriv = NULL;
int iRet;
assert(self);
pPriv = (pDoCho) self->pPrivate;
assert(pPriv);
pPriv->iError = 0;
/* first open the connection to the serial port server and channel */
iRet = SerialOpen(&(pPriv->pData), pPriv->pHost, pPriv->iPort,
pPriv->iChannel);
if (iRet <= 0) {
pPriv->iError = iRet;
return 0;
}
/* configure the connection */
SerialConfig(&(pPriv->pData), 10000);
SerialATerm(&(pPriv->pData), "1\r\n");
SerialSendTerm(&(pPriv->pData), "\r");
pPriv->iStop = 0;
pPriv->tRefresh = 0; /* force a status request when first run */
/* start the update task */
if (pPriv->lTask == 0) {
pPriv->lTask = TaskRegister(pServ->pTasker,
DoChoTask, NULL, NULL, self, 1);
}
return 1;
}
/*------------------------------------------------------------------------*/
static int DoChoClose(pCodri self)
{
pDoCho pPriv = NULL;
int iRet;
long lVal;
assert(self);
pPriv = (pDoCho) self->pPrivate;
assert(pPriv);
if (pPriv->pData) {
SerialClose(&(pPriv->pData));
pPriv->pData = NULL;
}
return 1;
}
/*------------------------------------------------------------------------*/
static int DoChoDelete(pCodri self)
{
pDoCho pPriv = NULL;
assert(self);
pPriv = (pDoCho) self->pPrivate;
assert(pPriv);
if (pPriv->pData) {
SerialClose(&(pPriv->pData));
pPriv->pData = NULL;
}
if (pPriv->pHost)
free(pPriv->pHost);
if (pPriv->pPar)
DeleteStringDict(pPriv->pPar);
free(pPriv);
return 1;
}
/*--------------------------------------------------------------------------*/
static int DoChoSetPar2(pCodri self, char *parname, char *pValue)
{
pDoCho pPriv = NULL;
char pCommand[80], pReply[132];
char pState[20];
int iRet;
assert(self);
pPriv = (pDoCho) self->pPrivate;
assert(pPriv);
/* deal with our four parameters */
if (strcmp(parname, "chopper1.nspee") == 0) {
sprintf(pCommand, "nspee 1 %s", pValue);
} else if (strcmp(parname, "chopper2.nspee") == 0) {
iRet = StringDictGet(pPriv->pPar, "chopper2.state", pState, 19);
if (iRet && strstr(pState, "async") != NULL) {
sprintf(pCommand, "nspee 2 %s", pValue);
} else {
pPriv->iError = BADSYNC;
return 0;
}
} else if (strcmp(parname, "chopper2.nphas") == 0) {
sprintf(pCommand, "nphas 2 %s", pValue);
} else if (strcmp(parname, "chopper1.nphas") == 0) {
sprintf(pCommand, "nphas 1 %s", pValue);
} else if (strcmp(parname, "chopper2.ratio") == 0) {
sprintf(pCommand, "ratio 2 %s", pValue);
} else {
pPriv->iError = UNDRIVABLE;
return 0;
}
iRet = SerialWriteRead(&(pPriv->pData), pCommand, pReply, 131);
if (iRet != 1) {
pPriv->iError = iRet;
return 0;
}
if (strstr(pReply, "error") != NULL) {
pPriv->iError = CHOPERROR;
strlcpy(pPriv->pError, pReply, 79);
return 0;
} else {
pPriv->iError = 0;
}
pPriv->iBusy = 1;
return 1;
}
/*-------------------------------------------------------------------------*/
static int DoChoHalt(pCodri self)
{
pDoCho pPriv = NULL;
assert(self);
pPriv = (pDoCho) self->pPrivate;
assert(pPriv);
/*
there is no documented way to stop the Dornier chopper
system. This at least makes SICS happy.
*/
pPriv->iError = BADSTOP;
pPriv->iBusy = 0;
return 1;
}
/*---------------------------------------------------------------------------*/
static int DoChoSetPar(pCodri self, char *parname, float fValue)
{
char pValue[50];
pDoCho pPriv = NULL;
assert(self);
pPriv = (pDoCho) self->pPrivate;
assert(pPriv);
if (strstr(parname, "nspee") != NULL) {
sprintf(pValue, "%d", (int) fValue);
} else if (strstr(parname, "ratio") != NULL) {
sprintf(pValue, "%d", (int) fValue);
pPriv->fRatio = (int) fValue;
} else if (strcmp(parname, "updateintervall") == 0) {
sprintf(pValue, "%d", (int) fValue);
StringDictUpdate(pPriv->pPar, "updateintervall", pValue);
pPriv->iRefreshIntervall = (int) fValue;
return 1;
} else {
sprintf(pValue, "%f", fValue);
}
return DoChoSetPar2(self, parname, pValue);
}
/*----------------------------------------------------------------------*/
static int DoChoGetPar(pCodri self, char *parname,
char *pBuffer, int iBufLen)
{
pDoCho pPriv = NULL;
int iRet;
assert(self);
pPriv = (pDoCho) self->pPrivate;
assert(pPriv);
if (pPriv->iError != 0) {
self->GetError(self, &iRet, pBuffer, iBufLen);
return 0;
}
iRet = StringDictGet(pPriv->pPar, parname, pBuffer, iBufLen);
if (!iRet) {
pPriv->iError = UNKNOWNPAR;
return 0;
}
return 1;
}
/*-----------------------------------------------------------------------*/
static int DoChoCheckPar(pCodri self, char *parname)
{
pDoCho pPriv = NULL;
char pVal1[20], pVal2[20];
float fTarget, fIst, fDelta;
int iRet;
assert(self);
pPriv = (pDoCho) self->pPrivate;
assert(pPriv);
/* check the busy flag first */
if (pPriv->iBusy)
return HWBusy;
/* was there an error in the status show? */
if (pPriv->iError != 0) {
return HWFault;
}
/* updateintervall is always HWIdle */
if (strcmp(parname, "updateintervall") == 0) {
return HWIdle;
}
/* OK, got a new status let us check the parameter */
/* chopper 1 speed */
if (strcmp(parname, "chopper1.nspee") == 0) {
iRet = StringDictGet(pPriv->pPar, "chopper1.nspee", pVal1, 19);
iRet += StringDictGet(pPriv->pPar, "chopper1.aspee", pVal2, 19);
if (iRet != 2) {
pPriv->iError = PARERROR;
return HWFault;
}
sscanf(pVal1, "%f", &fTarget);
sscanf(pVal2, "%f", &fIst);
fDelta = fTarget - fIst;
if (fDelta < 0.0)
fDelta = -fDelta;
if (fDelta > 50) {
return HWBusy;
} else {
return HWIdle;
}
}
/* chopper 2 speed */
if (strcmp(parname, "chopper2.nspee") == 0) {
iRet = StringDictGet(pPriv->pPar, "chopper2.nspee", pVal1, 19);
iRet += StringDictGet(pPriv->pPar, "chopper2.aspee", pVal2, 19);
if (iRet != 2) {
pPriv->iError = PARERROR;
return HWFault;
}
sscanf(pVal1, "%f", &fTarget);
sscanf(pVal2, "%f", &fIst);
fDelta = fTarget - fIst;
if (fDelta < 0.0)
fDelta = -fDelta;
if (fDelta > 5.) {
return HWBusy;
} else {
return HWIdle;
}
}
/* phase */
if (strcmp(parname, "chopper2.nphas") == 0) {
iRet = StringDictGet(pPriv->pPar, "chopper2.dphas", pVal1, 19);
sscanf(pVal1, "%f", &fDelta);
if (fDelta < 0.)
fDelta = -fDelta;
if (fDelta > 0.3) {
return HWBusy;
} else {
return HWIdle;
}
}
if (strcmp(parname, "chopper1.nphas") == 0) {
iRet = StringDictGet(pPriv->pPar, "chopper1.dphas", pVal1, 19);
sscanf(pVal1, "%f", &fDelta);
if (fDelta < 0.)
fDelta = -fDelta;
if (fDelta > 0.3) {
return HWBusy;
} else {
return HWIdle;
}
}
/* ratio */
if (strcmp(parname, "chopper2.ratio") == 0) {
iRet = StringDictGet(pPriv->pPar, "chopper2.ratio", pVal1, 19);
sscanf(pVal1, "%f", &fIst);
fDelta = fIst - pPriv->fRatio;
if (fDelta < 0.)
fDelta = -fDelta;
if (fDelta > 0.3) {
return HWBusy;
} else {
return HWIdle;
}
}
pPriv->iError = UNKNOWNPAR;
return HWFault;
}
/*-------------------------------------------------------------------------*/
static int DoChoError(pCodri self, int *iCode, char *pError, int iLen)
{
pDoCho pPriv = NULL;
assert(self);
pPriv = (pDoCho) self->pPrivate;
assert(pPriv);
*iCode = pPriv->iError;
switch (pPriv->iError) {
case UNDRIVABLE:
strlcpy(pError, "Parameter is not drivable", iLen);
break;
case UNKNOWNPAR:
strlcpy(pError, "Parameter is unknown", iLen);
break;
case PARERROR:
strlcpy(pError, "Internal parameter error", iLen);
break;
case BADSYNC:
strlcpy(pError, "Cannot drive slave chopper", iLen);
break;
case CHOPERROR:
strlcpy(pError, pPriv->pError, iLen);
break;
case BADSTOP:
strlcpy(pError,
"User called STOP. WARNING: chopper is still untamed!", iLen);
break;
default:
SerialError(pPriv->iError, pError, iLen);
break;
}
pPriv->iError = 0;
return 1;
}
/*------------------------------------------------------------------------*/
static int DoChoFix(pCodri self, int iCode)
{
pDoCho pPriv = NULL;
int iRet;
assert(self);
pPriv = (pDoCho) self->pPrivate;
assert(pPriv);
switch (iCode) {
/* 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:
case NOCONNECTION:
SerialForceClose(&(pPriv->pData));
pPriv->pData = NULL;
iRet = SerialOpen(&(pPriv->pData), pPriv->pHost,
pPriv->iPort, pPriv->iChannel);
if (iRet == 1) {
return CHREDO;
} else {
return CHFAIL;
}
break;
case EL734__FORCED_CLOSED:
iRet = DoChoInit(self);
if (iRet) {
return CHREDO;
} else {
return CHFAIL;
}
break;
default:
return CHFAIL;
break;
}
return CHFAIL;
}
/*-------------------------------------------------------------------------*/
pCodri MakeDoChoDriver(char *pHost, int iPort, int iChannel, int iSingle)
{
pCodri pNew = NULL;
pDoCho pPriv = NULL;
char *pText;
/* allocate memory */
pText = (char *) malloc(4096 * sizeof(char));
pNew = (pCodri) malloc(sizeof(Codri));
pPriv = (pDoCho) malloc(sizeof(DoCho));
if (!pText || !pNew || !pPriv) {
return NULL;
}
memset(pText, 0, 4096);
memset(pNew, 0, sizeof(Codri));
memset(pPriv, 0, sizeof(DoCho));
/* initialize private data structure */
pPriv->pHost = strdup(pHost);
pPriv->iPort = iPort;
pPriv->iChannel = iChannel;
pPriv->pData = NULL;
pPriv->iRefreshIntervall = 60;
pPriv->pPar = CreateStringDict();
pPriv->tRefresh = time(NULL);
pPriv->iSingle = iSingle;
if (!pPriv->pPar) {
free(pText);
free(pNew);
free(pPriv);
return NULL;
}
/* install codri */
pNew->Init = DoChoInit;
pNew->Close = DoChoClose;
pNew->Delete = DoChoDelete;
pNew->SetPar = DoChoSetPar;
pNew->SetPar2 = DoChoSetPar2;
pNew->GetPar = DoChoGetPar;
pNew->CheckPar = DoChoCheckPar;
pNew->GetError = DoChoError;
pNew->TryFixIt = DoChoFix;
pNew->Halt = DoChoHalt;
pNew->pParList = pText;
strcpy(pNew->pParList, "updateintervall,");
StringDictAddPair(pPriv->pPar, "updateintervall", "60");
pNew->pPrivate = pPriv;
return pNew;
}

View File

@ -1,708 +0,0 @@
/*------------------------------------------------------------------------
Another driver for a Dornier velocity selector. This is for a newer
version of the velocity selector driver as delivered with SANS-2. It
also uses a direct connection to the terminal server without David Maden's
SerPortServer program in between.
I believe this is for Dornier software version: NGS037 of 2002.
The protocoll is inconsistent: status messages come back with a <cr>,
command responses tend to come back with a \ and no <cr>!
There is a scheme here: while waiting for status reponses during driving,
the last status read is used for any requests.
copyright: see file COPYRIGHT
Mark Koennecke, July 2003
---------------------------------------------------------------------------*/
#include <sics.h>
#include <string.h>
#include <math.h>
#include <tcl.h>
#include <time.h>
#include <fortify.h>
#include <rs232controller.h>
typedef struct __VelSelDriv *pVelSelDriv;
#include <velodriv.h>
#include "velodorn.h"
/* VELO* MUST be the same as in velo.i!*/
#define VELOREDO 2
#define VELOFAIL 0
#define VELOOK 1
#define VSNOCON 0
#define VSOK 1
#define VSACCEL -7
#define VSFAIL -2
/* start speed */
#define STARTSPEED 3100
/*--------- special Dornier conditions*/
#define STARTED -88
#define HALTREQ -77
/* INVALIDSTATUS is defined in velodorn.h */
#define TARGETREJECTED -7001
#define NOSTATUS -7002
/*---------- DORNIER status modes */
#define STATSEND 1
#define STATREAD 2
/*----------------------------- The private data structure ---------------*/
typedef struct {
prs232 controller;
int iTimeOut;
int iLastError;
time_t t_End;
time_t t_timeout;
float fTarget;
float fLastRPM;
int statusMode;
DornierStatus lastStatus;
int minRPM; /* the minimum control speed of the thing */
int haltCount;
int rejectCount;
int noStatus; /* flag which indicates that no valid status
has yet been read. Solves a starting
problem
*/
int firstStatus; /* at times the nvs does not send
the reply to the first status
request after starting. This flag
helps to suppress an error message
which may be confusing to loosers
*/
} Dornier, *pDornier;
/*------------------------------------------------------------------*/
static int requestDornierStatus(pDornier pDorn)
{
int status;
status = writeRS232(pDorn->controller, "???\n", 4);
if (status < 0) {
pDorn->iLastError = status;
return 0;
}
return 1;
}
/*------------------------------------------------------------------*/
static int readAndInterpretStatus(pDornier pDorn, DornierStatus * DStatus)
{
int status, datalen;
char reply[512];
datalen = 512;
status = readRS232TillTerm(pDorn->controller, reply, &datalen);
if (status < 0) {
pDorn->iLastError = status;
return 0;
}
if (strlen(reply) < 80) {
pDorn->iLastError = INVALIDSTATUS;
pDorn->statusMode = STATSEND;
return 0;
}
DecodeNewDornierStatus(reply, DStatus);
if (pDorn->noStatus == 1) {
pDorn->noStatus = 0;
}
return 1;
}
/*-----------------------------------------------------------------*/
static int takeControl(pDornier pDorn)
{
int iRet;
char pError[80];
setRS232ReplyTerminator(pDorn->controller, "\\");
iRet = transactRS232(pDorn->controller, "REM\n", 4, pError, 79);
setRS232ReplyTerminator(pDorn->controller, "\n");
return iRet;
}
/*--------------------------------------------------------------------*/
static int GetDornierPos(pVelSelDriv self, float *fPos)
{
pDornier pDorn = NULL;
DornierStatus DStatus;
int status;
assert(self);
pDorn = (pDornier) self->pPrivate;
if (pDorn->statusMode == STATSEND) {
if (!requestDornierStatus(pDorn)) {
*fPos = -9999.;
return 0;
}
if (!readAndInterpretStatus(pDorn, &DStatus)) {
*fPos = -9999.;
return 0;
}
pDorn->lastStatus = DStatus;
}
*fPos = pDorn->lastStatus.cur_rpm;
pDorn->fLastRPM = pDorn->lastStatus.cur_rpm;
return 1;
}
/*--------------------------------------------------------------------------*/
static int DornierHalt(pVelSelDriv self)
{
pDornier pDorn = NULL;
int iRet;
char pCom[50];
char pAnswer[80];
assert(self);
pDorn = (pDornier) self->pPrivate;
snprintf(pCom, 49, "SDR %d\n", pDorn->minRPM);
iRet = transactRS232(pDorn->controller, pCom, strlen(pCom), pAnswer, 79);
if (iRet < 1) {
pDorn->iLastError = iRet;
return 0;
}
return 1;
}
/*----------------------------------------------------------------------*/
static int DornierText(pVelSelDriv self, char *pText, int iTextLen)
{
pDornier pDorn = NULL;
int iRet, iErrStat;
DornierStatus sStatus;
char pBueffel[1024];
char pHelp[80];
assert(self);
pDorn = (pDornier) self->pPrivate;
/*
use cached status while waiting for reply during drive
*/
if (pDorn->statusMode == STATSEND) {
if (!requestDornierStatus(pDorn)) {
return 0;
}
if (!readAndInterpretStatus(pDorn, &sStatus)) {
return 0;
}
pDorn->lastStatus = sStatus;
} else {
sStatus = pDorn->lastStatus;
}
/* format it to a string */
sprintf(pHelp, "RPM: %d , should %d\n", sStatus.cur_rpm,
sStatus.nom_rpm);
strcpy(pBueffel, pHelp);
sprintf(pHelp, "State: %s\n", sStatus.rm);
strcat(pBueffel, pHelp);
sprintf(pHelp, "Current: %d\n", sStatus.pwr);
strcat(pBueffel, pHelp);
sprintf(pHelp, "Rotor T: %d, Housing T: %d\n", sStatus.rot_temp,
sStatus.cont_temp);
strcat(pBueffel, pHelp);
sprintf(pHelp, "Cooling: In-T: %d, Out-T: %d, Flow: %f\n",
sStatus.inl_temp, sStatus.outl_temp, sStatus.cool_wat);
strcat(pBueffel, pHelp);
sprintf(pHelp, "Vaccum: %f, Accel: %f", sStatus.vacuum, sStatus.accel);
strcat(pBueffel, pHelp);
strlcpy(pText, pBueffel, iTextLen);
return 1;
}
/*-------------------------------------------------------------------------*/
static int DornierRun(pVelSelDriv self, float fVal)
{
int iRet;
char pCommand[50], pAnswer[50], pText[132];
pDornier pDorn = NULL;
int startFlag = 0;
int i;
DornierStatus sStatus;
assert(self);
pDorn = (pDornier) self->pPrivate;
/*
make sure that a status was read before we do anything here,
otherwise we may be in deep trouble
*/
if (pDorn->statusMode == STATSEND) {
iRet = requestDornierStatus(pDorn);
if (iRet == 0) {
return 0;
}
}
iRet = readAndInterpretStatus(pDorn, &sStatus);
if (iRet == 0) {
return 0;
}
pDorn->lastStatus = sStatus;
/*
less then STARTSPEED, means halt in this case.
Accept this only after three times, see code in GetError as well.
*/
if (fVal < 0) {
fVal = -fVal;
}
memset(pCommand, 0, 50);
pDorn->rejectCount = 0;
if (fVal < STARTSPEED - 3 * self->fTolerance) {
if (pDorn->haltCount < 3) {
pDorn->iLastError = HALTREQ;
return 0;
}
strcpy(pCommand, "HAL\n");
setRS232ReplyTerminator(pDorn->controller, "\r");
pDorn->haltCount = 0;
pDorn->fTarget = fVal;
} else {
if (pDorn->lastStatus.cur_rpm < STARTSPEED - 3 * self->fTolerance) {
strcpy(pCommand, "SST\n");
startFlag = 1;
pDorn->fTarget = STARTSPEED;
setRS232ReplyTerminator(pDorn->controller, "\r");
} else {
setRS232ReplyTerminator(pDorn->controller, "\r");
sprintf(pCommand, "SDR %d\n", (int) fVal);
pDorn->fTarget = fVal;
}
}
iRet = transactRS232(pDorn->controller, pCommand, strlen(pCommand),
pAnswer, 49);
setRS232ReplyTerminator(pDorn->controller, "\n");
pDorn->firstStatus = 1;
if (iRet < 1) {
if (iRet != INCOMPLETE) {
pDorn->iLastError = iRet;
return 0;
}
}
pDorn->statusMode = STATSEND;
if (startFlag) {
pDorn->iLastError = STARTED;
return 0;
}
return 1;
}
/*---------------------------------------------------------------------*/
static int DornierError(pVelSelDriv self, int *iCode,
char *error, int iErrLen)
{
pDornier pDorn = NULL;
assert(self);
pDorn = (pDornier) self->pPrivate;
*iCode = pDorn->iLastError;
switch (pDorn->iLastError) {
case HALTREQ:
strlcpy(error, "Repeat command if you really want to HALT selector",
iErrLen);
pDorn->haltCount++;
break;
case STARTED:
strlcpy(error,
"Started selector, standby and check manually when ready",
iErrLen);
break;
case INVALIDSTATUS:
strlcpy(error, "Received invalid status reply", iErrLen);
break;
case TARGETREJECTED:
strlcpy(error, "VS in local mode or target out of range", iErrLen);
break;
case NOSTATUS:
strlcpy(error, "No successfull status request after 3 tries", iErrLen);
break;
default:
getRS232Error(pDorn->iLastError, error, iErrLen);
break;
}
return 1;
}
/*-------------------------------------------------------------------*/
static int DornierFixIt(pVelSelDriv self, int iCode)
{
pDornier pDorn = NULL;
int status, oldReject;
assert(self);
pDorn = (pDornier) self->pPrivate;
switch (iCode) {
case NOTCONNECTED:
status = initRS232(pDorn->controller);
if (status) {
return VELOREDO;
} else {
return VELOFAIL;
}
break;
case TIMEOUT:
case INCOMPLETE:
case INVALIDSTATUS:
return VELOREDO;
break;
case TARGETREJECTED:
if (pDorn->rejectCount >= 3) {
pDorn->rejectCount = 0;
return VELOFAIL;
}
oldReject = pDorn->rejectCount;
status = takeControl(pDorn);
if (status >= 1) {
DornierRun(self, pDorn->fTarget);
pDorn->rejectCount = oldReject + 1;
return VELOREDO;
}
return VELOFAIL;
break;
default:
return VELOFAIL;
}
}
/*---------------------------------------------------------------------*/
static int statusSendHandler(pDornier pDorn)
{
int status;
if (!requestDornierStatus(pDorn)) {
return VSFAIL;
}
pDorn->t_timeout = time(NULL) + pDorn->iTimeOut / 1000;
pDorn->statusMode = STATREAD;
return VSACCEL;
}
/*------------------------------------------------------------------*/
static int evaluateStatus(pVelSelDriv self, int *iCode)
{
int status;
DornierStatus sStatus;
char pCommand[80];
char pAnswer[80];
float fDelta;
static int iCount = 0;
pDornier pDorn = NULL;
pDorn = (pDornier) self->pPrivate;
pDorn->statusMode = STATSEND;
status = readAndInterpretStatus(pDorn, &sStatus);
if (!status) {
if (pDorn->firstStatus == 1) {
pDorn->firstStatus = 0;
return VSACCEL;
}
return VELOFAIL;
}
*iCode = ROTMOVE;
/*
sometimes the velocity selector does not accept a new target:
Two reasons: a) it is local, b) out of range
Check for this here as it is the only place appropriate.
*/
fDelta = sStatus.nom_rpm - pDorn->fTarget;
if (fDelta < 0) {
fDelta = -fDelta;
}
if (fDelta > self->fTolerance) {
pDorn->iLastError = TARGETREJECTED;
return VSFAIL;
}
/*
This code considers the velocity selector arrived if it reads
four times a difference between requested speed and actual speed
below difference
*/
pDorn->fLastRPM = sStatus.cur_rpm;
fDelta = sStatus.cur_rpm - sStatus.nom_rpm;
if (fDelta < 0) {
fDelta = -fDelta;
}
if (fDelta > self->fTolerance) {
iCount = 0;
return VSACCEL;
} else {
iCount++;
if (iCount > 4) {
return VSOK;
} else {
return VSACCEL;
}
}
}
/*---------------------------------------------------------------------*/
static int statusReceiveHandler(pVelSelDriv self, int *iCode)
{
int status;
pDornier pDorn = NULL;
pDorn = (pDornier) self->pPrivate;
status = availableRS232(pDorn->controller);
if (!status) {
if (time(NULL) > pDorn->t_timeout) {
pDorn->iLastError = TIMEOUT;
pDorn->statusMode = STATSEND;
return VELOFAIL;
} else {
return VSACCEL;
}
}
return evaluateStatus(self, iCode);
}
/*--------------------------------------------------------------------------
The Dornier takes a long time to answer a status message. In order to keep
SICS responsive the following state machine is implemented:
- a status request is sent.
- next data availability will be checked, if available: process!
---------------------------------------------------------------------------*/
static int DornierStatNew(pVelSelDriv self, int *iCode, float *fCur)
{
pDornier pDorn = NULL;
int status;
assert(self);
pDorn = (pDornier) self->pPrivate;
if (pDorn->statusMode == STATSEND) {
return statusSendHandler(pDorn);
} else {
status = statusReceiveHandler(self, iCode);
*fCur = pDorn->fLastRPM;
return status;
}
}
/*------------------------------------------------------------------------*/
static int DornierLoss(pVelSelDriv self, float *fLoss)
{
pDornier pDorn = NULL;
int iRet, iErrStat, iDelta;
DornierStatus DStatus;
char pCommand[] = { "BRE\n" };
char pAnswer[80];
static int iCount;
static int iError;
int i;
assert(self);
pDorn = (pDornier) self->pPrivate;
/* send a command */
iRet = transactRS232(pDorn->controller, pCommand, strlen(pCommand),
pAnswer, 79);
if (iRet < 1) {
pDorn->iLastError = iRet;
return 0;
}
/* wait 10 seconds before doing anything */
SicsWait(10);
/* loop until back to speed again */
for (i = 0; i < 100; i++) {
if (!requestDornierStatus(pDorn)) {
return 0;
}
if (!readAndInterpretStatus(pDorn, &DStatus)) {
return 0;
}
iError = 0;
iDelta = DStatus.cur_rpm - DStatus.nom_rpm;
if (iDelta < 0) {
iDelta = -iDelta;
}
if (iDelta < 15) {
iCount++;
if (iCount > 4) {
break;
}
} else {
iCount = 0;
}
}
*fLoss = DStatus.pwr;
return 1;
}
/*-------------------------------------------------------------------------*/
static void DornierKill(void *pData)
{
pDornier pDorn = NULL;
pDorn = (pDornier) pData;
assert(pDorn);
writeRS232(pDorn->controller, "TTY\n", 4);
KillRS232(pDorn->controller);
free(pDorn);
}
/*------------------------------------------------------------------------*/
static int DornierInit(pVelSelDriv self, SConnection * pCon)
{
pDornier pDorn = NULL;
int iRet, iError;
float fRot;
char pError[80], pBueffel[256];
assert(self);
pDorn = (pDornier) self->pPrivate;
assert(pDorn);
iRet = initRS232(pDorn->controller);
if (iRet < 0) {
return 1;
}
setRS232SendTerminator(pDorn->controller, "\n");
setRS232Timeout(pDorn->controller, pDorn->iTimeOut);
setRS232Debug(pDorn->controller, 0);
/*
tell him that we want control.
Funny enough no <cr> or <nl> is sent in the reply to this.
*/
iRet = takeControl(pDorn);
if (iRet <= 1) {
sprintf(pBueffel,
"ERROR: %s while switching velocity selector to remote",
pError);
SCWrite(pCon, pBueffel, eError);
}
/*
check which status the velo is in
*/
pDorn->statusMode = STATSEND;
return 1;
}
/*-------------------------------------------------------------------------*/
pVelSelDriv VSCreateDornier2003(char *name, Tcl_Interp * pTcl)
{
pVelSelDriv pNew = NULL;
pDornier pDorn = NULL;
char *pPtr = NULL;
int iVal, iRet, iPort;
char pHost[132];
/* the most likely error is the parameters specified are wrong!
So check this first. We''ll use Tcl's result for error reporting.
name is the name of an Tcl array which should hold the info
necessary
*/
/* allocate a Dornier structure */
pDorn = (pDornier) malloc(sizeof(Dornier));
if (!pDorn) {
return NULL;
}
memset(pDorn, 0, sizeof(Dornier));
/* host name */
pPtr = (char *) Tcl_GetVar2(pTcl, name, "Host", TCL_GLOBAL_ONLY);
if (!pPtr) {
Tcl_AppendResult(pTcl, "ERROR: no hostname found in", name, NULL);
free(pDorn);
return NULL;
}
strlcpy(pHost, pPtr, 131);
/* port number */
pPtr = (char *) Tcl_GetVar2(pTcl, name, "Port", TCL_GLOBAL_ONLY);
if (!pPtr) {
Tcl_AppendResult(pTcl, "ERROR: no port number found in", name, NULL);
free(pDorn);
return NULL;
}
iRet = Tcl_GetInt(pTcl, pPtr, &iPort);
if (iRet != TCL_OK) {
free(pDorn);
return NULL;
}
/* time out. This one gets defaulted when not specified */
pPtr = (char *) Tcl_GetVar2(pTcl, name, "Timeout", TCL_GLOBAL_ONLY);
if (!pPtr) {
pDorn->iTimeOut = 1000;
} else {
iRet = Tcl_GetInt(pTcl, pPtr, &iVal);
if (iRet != TCL_OK) {
pDorn->iTimeOut = 1000;
}
pDorn->iTimeOut = iVal;
}
/* minimum control speed */
pPtr = (char *) Tcl_GetVar2(pTcl, name, "MinControl", TCL_GLOBAL_ONLY);
if (!pPtr) {
pDorn->minRPM = 3100;
} else {
iRet = Tcl_GetInt(pTcl, pPtr, &iVal);
if (iRet != TCL_OK) {
pDorn->minRPM = 3100;
}
pDorn->minRPM = iVal;
}
/* business as usual: allocate memory */
pNew = (pVelSelDriv) malloc(sizeof(VelSelDriv));
if (!pNew) {
return NULL;
}
/* zero the world */
memset(pNew, 0, sizeof(VelSelDriv));
pNew->pPrivate = pDorn;
pDorn->controller = createRS232(pHost, iPort);
if (!pDorn->controller) {
DornierKill(pNew->pPrivate);
free(pNew);
return NULL;
}
pDorn->noStatus = 1;
/* initialise function pointers */
pNew->DeletePrivate = DornierKill;
pNew->Halt = DornierHalt;
pNew->GetError = DornierError;
pNew->TryAndFixIt = DornierFixIt;
pNew->GetRotation = GetDornierPos;
pNew->SetRotation = DornierRun;
pNew->GetStatus = DornierStatNew;
pNew->GetDriverText = DornierText;
pNew->GetLossCurrent = DornierLoss;
pNew->Init = DornierInit;
/* done it */
return pNew;
}

View File

@ -1,640 +0,0 @@
/*----------------------------------------------------------------------------
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 readTime(pECBCounter pPriv, float *time)
{
int status;
Z80_reg in, out;
Ecb_pack data;
in.c = (unsigned char) 0;
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;
*time = (float) data.result / (float) pPriv->tfreq;
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 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 ECBGetStatus(struct __COUNTER *self, float *fControl)
{
pECBCounter pPriv = (pECBCounter) self->pData;
int status, result, scaler;
Z80_reg in, out;
int count, beam;
float time;
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;
readTime(pPriv, fControl);
} else {
scaler = pPriv->control;
readScaler(pPriv, scaler, &count);
*fControl = (float) count;
}
if (*fControl > self->fPreset + 1.) {
ECBHalt(self);
}
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 ECBTransfer(struct __COUNTER *self)
{
int status, count, i;
pECBCounter pPriv = NULL;
assert(self);
pPriv = (pECBCounter) self->pData;
assert(pPriv);
/*
read time
*/
status = readTime(pPriv, &self->fTime);
if (status <= 0) {
self->iErrorCode = COMMERROR;
return HWFault;
}
/*
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:
strlcpy(errorText, "Communication error with ECB", errlen);
break;
case TOMANYCOUNTS:
strlcpy(errorText, "Preset is to high!", errlen);
break;
case NOSEND:
strlcpy(errorText, "Cannot send naked data to ECB", errlen);
break;
case UNKNOWNPAR:
strlcpy(errorText, "parameter unknown", errlen);
break;
case INVALIDCOUNTER:
strlcpy(errorText, "Invalid counter number requested, 0-7 allowed",
errlen);
break;
case INVALIDPRESCALER:
strlcpy(errorText, "Invalid prescaler value, allowed 1 or 10", errlen);
break;
case BADFREQ:
strlcpy(errorText, "Bad timer frequency: 10 or 1000 allowed", errlen);
break;
default:
sprintf(pBueffel, "Unknown error code %d", self->iErrorCode);
strlcpy(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)
{
strlcpy(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->iNoOfMonitors = 8;
self->pData = pPriv;
return self;
}

View File

@ -1,17 +0,0 @@
/*-------------------------------------------------------------------------
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

1370
ecbdriv.c

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +0,0 @@
/*------------------------------------------------------------------------
this is a motor driver for the Risoe motor controllers within the
ECB system. The motor is controlled through functions invoked in the
Z80 processor of the ECB system which is connected through a GPIB
bus to the wider world. This driver has to do a lot of extra things:
- it has to convert from physical values to motor steps.
- Quite a few parameters, such as ramping parameters,
have to be downloaded to the ECB
- Risoe motors may have a virtual encoder or a real encoder.
- The motor may have to control air cushions as well.
- Tricky backlash handling. Backlash handling ensures that a position is
always arrived at from a defined direction. If backlash is applied
a restart flag is set in ECBRunTo. ECBGetStatus checks for that and
causes the motor to drive back to the position actually desired.
This driver support only P2048a motor controllers, as these are the
only ones which seem to have arrived at PSI. The P1648 and Tridynamic
things are not supported.
Multiplexed motors: Originally the ECB supported 24 motors. This did
prove to be not enough. Therefore another device called P2234e was
introduced which allowed to run 8 motors from one controller port. In this
case the motor parameters have to be copied to the ECB before
driving the motor. Multiplexing is selected through the parameter MULT.
MULT 0 means no multiplexing, MULT > 0 makes MULT the number of the
motor in the multiplexer. MULT is now also used to flag a download of
parameters to the ECB. In such a case MULT is -1.
Some of this code was taken from the tascom driver for the ECB.
copyright: see file COPYRIGHT
Mark Koennecke, January 2003
--------------------------------------------------------------------------*/
#ifndef ECBDRIV
#define ECBDRIV
MotorDriver *CreateECBMotor(SConnection * pCon, int argc, char *argv[]);
void KillECBMotor(void *driver);
#endif

730
eigermono.c Normal file
View File

@ -0,0 +1,730 @@
/**
* This is a special monochromator module for EIGER. EIGER has a ton of
* specialities:
*
* - d2r and d2l must be moved with a2rot in order to maintain the slit
* width a2w
* - When interrupting a2, a2 must be stooped and d2l, d2r aligned afterwards.
* - There is a special drivable a2w which is that slit width.
* - When driving the monochromator energy, then not only curvatures but also
* a monochromator translation must be driven. This needs extra parameters
* - There are two additional virtual motors: a2 and a2w.
* - There are multiple modes of operation:
* * Driving only a2
* * Driving only a2w
* * Driving the whole monochromator
*
* All this shite is addressed in this module. This is already a second version,
* the old version contained a virtual motor for a2, a2w only. This fell over because
* it did not account for the monochromator translation and a rare bug could not be
* fixed in the old module.
*
* Mark Koennecke, February 2013
*/
#include <math.h>
#include <sics.h>
#include <tasub.h>
#include <sicsobj.h>
#include <sicshipadaba.h>
/* motors */
#define A1 0
#define A2ROT 1
#define D2R 2
#define D2L 3
#define MCV 4
#define MCH 5
#define MTX 6
static char *motNames[] = {
"a1",
"a2rot",
"d2r",
"d2l",
"mcv",
"mch",
"mt"
};
/* states */
#define IDLE 0
#define STARTMONO 1
#define STARTA2 2
#define STARTA2W 3
#define WAITING 4
#define WAITA2 5
#define WAITSLIT 6
/* constants */
#define RIGHTSIZE -3.5
#define LEFTSIZE -101.5
#define ABS(x) (x < 0 ? -(x) : (x))
#define MOTPREC .1
#define NOTSTARTED -100
/*------------------- module private data structure -------------*/
typedef struct {
pmaCrystal mono;
ptasUB tasub;
pIDrivable drivs[7];
void *motData[7];
double a2wTarget;
double a2Target;
int state;
long waitID;
}eigerMono, *peigerMono;
/*----------------------------------------------------------------
This routine can return either OKOK or HWFault when thing
go wrong. However, the return value of Halt is usually ignored!
------------------------------------------------------------------*/
static int EIMOHalt(void *data) {
pSICSOBJ self = NULL;
int i;
self = (pSICSOBJ)data;
peigerMono mono = (peigerMono)self->pPrivate;
for(i = 0; i < 7; i++){
mono->drivs[i]->Halt(mono->motData[i]);
}
mono->state = WAITA2;
return OKOK;
}
/*----------------------------------------------------------------
This routine can return either 1 or 0. 1 means the position can
be reached, 0 NOT
If 0, error shall contain up to errlen characters of information
about which limit was violated
------------------------------------------------------------------*/
static int EIMOCheckLimits(void *data, float val,
char *error, int errlen){
pSICSOBJ self = NULL;
self = (pSICSOBJ)data;
peigerMono mono = (peigerMono)self->pPrivate;
/*
does not make sense in this context
*/
return 1;
}
/*----------------------------------------------------------------
This routine can return 0 when a limit problem occurred
OKOK when the motor was successfully started
HWFault when a problem occured starting the device
Possible errors shall be printed to pCon
For real motors, this is supposed to try at least three times
to start the motor in question
val is the value to drive the motor too
------------------------------------------------------------------*/
static long EIMOSetValue(void *data, SConnection *pCon, float val){
pSICSOBJ self = NULL;
self = (pSICSOBJ)data;
peigerMono mono = (peigerMono)self->pPrivate;
mono->a2Target = val;
mono->state = STARTMONO;
return 1;
}
/*-----------------------------------------------------------------*/
static long EIMOSetA2Value(void *data, SConnection *pCon, float val){
pSICSOBJ self = NULL;
self = (pSICSOBJ)data;
peigerMono mono = (peigerMono)self->pPrivate;
mono->a2Target = val;
mono->state = STARTA2;
return 1;
}
/*----------------------------------------------------------------*/
static long EIMOSetA2WValue(void *data, SConnection *pCon, float val){
pSICSOBJ self = NULL;
self = (pSICSOBJ)data;
peigerMono mono = (peigerMono)self->pPrivate;
mono->a2wTarget = val;
mono->state = STARTA2W;
return 1;
}
/*------------------------------------------------------------------------*/
static void writeMotPos(SConnection * pCon, int silent, char *name,
float val, float target)
{
char pBueffel[132];
if (silent != 1) {
snprintf(pBueffel, 131, "Driving %5s from %8.3f to %8.3f",
name, val, target);
SCWrite(pCon, pBueffel, eLog);
}
}
/*--------------------------------------------------------------------------*/
static long startTASMotor(pMotor mot, SConnection * pCon, char *name,
double target, int silent, int stopFixed)
{
float val, fixed, precision = MOTPREC;
long status = NOTSTARTED;
char buffer[132];
pIDrivable pDriv = NULL;
pDummy dum = NULL;
pDynString mes = NULL;
dum = (pDummy)mot;
GetDrivablePosition(mot, pCon,&val);
if(strcmp(dum->pDescriptor->name,"Motor") == 0){
MotorGetPar(mot,"precision",&precision);
MotorGetPar(mot, "fixed", &fixed);
if (ABS(fixed - 1.0) < .1) {
if(stopFixed == 0){
snprintf(buffer, 131, "WARNING: %s is FIXED", name);
SCWrite(pCon, buffer, eLog);
}
return NOTSTARTED;
}
}
mot->stopped = 0;
if (ABS(val - target) > precision) {
status = StartDriveTask(mot, pCon, name, (float)target);
if(status < 0){
SCPrintf(pCon,eLog,"ERROR: failed to drive %s to %f", name, target);
}
/*
to force updates on targets
*/
InvokeNewTarget(pServ->pExecutor, name, target);
writeMotPos(pCon, silent, name, val, target);
return status;
}
return NOTSTARTED;
}
/*---------------------------------------------------------------*/
static void calcSlitTargets(peigerMono self, float a2, float *d2r, float *d2l)
{
*d2r = RIGHTSIZE - a2 + self->a2wTarget/2;
*d2l = LEFTSIZE + a2 + self->a2wTarget/2;
}
/*--------------------------------------------------------------*/
static void startMono(pSICSOBJ self, SConnection *pCon)
{
int stopFixed = 0;
int silent = 1;
int status;
double curve;
float d2r, d2l, mtx;
peigerMono mono = (peigerMono)self->pPrivate;
hdbValue mta, mtb;
assert(mono != NULL);
double val = mono->a2Target;
mono->waitID = GetTaskGroupID(pServ->pTasker);
silent = mono->tasub->silent;
/*
the meat: A1, A2
*/
status = startTASMotor((pMotor)mono->motData[A1], pCon, "a1",
val / 2., silent, stopFixed);
if (status < 0 && status != NOTSTARTED) {
SCWrite(pCon,"ERROR: failed to start required motor A1",eLogError);
return;
}
if(status != NOTSTARTED){
AddTaskToGroup(pServ->pTasker,status, mono->waitID);
}
status = startTASMotor((pMotor)mono->motData[A2ROT], pCon, "a2",
val, silent,stopFixed);
if (status < 0 && status != NOTSTARTED) {
SCWrite(pCon,"ERROR: failed to start required motor A2",eLogError);
return ;
}
if(status != NOTSTARTED){
AddTaskToGroup(pServ->pTasker,status, mono->waitID);
}
/*
the slits
*/
calcSlitTargets(mono,val,&d2r,&d2l);
status = startTASMotor((pMotor)mono->motData[D2R], pCon, "d2r",
d2r, silent,stopFixed);
if (status < 0 && status != NOTSTARTED) {
SCWrite(pCon,"WARNING: monochromator d2r failed to start", eLog);
SCSetInterrupt(pCon,eContinue);
} else {
AddTaskToGroup(pServ->pTasker,status, mono->waitID);
}
status = startTASMotor((pMotor)mono->motData[D2L], pCon, "d2l",
d2l, silent,stopFixed);
if (status < 0 && status != NOTSTARTED) {
SCWrite(pCon,"WARNING: monochromator d2l failed to start", eLog);
SCSetInterrupt(pCon,eContinue);
} else {
AddTaskToGroup(pServ->pTasker,status, mono->waitID);
}
/*
curvatures
*/
curve = maCalcHorizontalCurvature(*mono->mono,
val);
status = startTASMotor((pMotor)mono->motData[MCH], pCon, "mch",
curve, silent,stopFixed);
if (status < 0 && status != NOTSTARTED) {
SCWrite(pCon,"WARNING: monochromator horizontal curvature motor failed to start", eLog);
SCSetInterrupt(pCon,eContinue);
}else {
AddTaskToGroup(pServ->pTasker,status,mono->waitID);
}
curve = maCalcVerticalCurvature(*mono->mono,
val);
status = startTASMotor((pMotor)mono->motData[MCV], pCon, "mcv",
curve, silent,stopFixed);
if (status < 0 && status != NOTSTARTED) {
SCWrite(pCon,"WARNING: monochromator vertical curvature motor failed to start", eLog);
SCSetInterrupt(pCon,eContinue);
} else {
AddTaskToGroup(pServ->pTasker,status, mono->waitID);
}
/*
the translation
*/
if(status > 0){
/*
only run mt when mcv started
*/
SICSHdbGetPar(self,pCon,"MTA",&mta);
SICSHdbGetPar(self,pCon,"MTB",&mtb);
mtx = mta.v.doubleValue + mtb.v.doubleValue*pow(curve,.75);
status = startTASMotor((pMotor)mono->motData[MTX], pCon, "mt",
mtx, silent,stopFixed);
if (status < 0 && status != NOTSTARTED) {
SCWrite(pCon,"WARNING: monochromator translation motor failed to start", eLog);
SCSetInterrupt(pCon,eContinue);
} else {
AddTaskToGroup(pServ->pTasker,status, mono->waitID);
}
}
}
/*--------------------------------------------------------------*/
static void startA2(peigerMono mono, SConnection *pCon)
{
float d2r, d2l;
int status;
mono->waitID = GetTaskGroupID(pServ->pTasker);
status = StartDriveTask(mono->motData[A2ROT],pCon,
"a2rot",mono->a2Target);
if(status > 0) {
AddTaskToGroup(pServ->pTasker,status,mono->waitID);
} else {
return;
}
calcSlitTargets(mono,mono->a2Target,&d2r,&d2l);
status = StartDriveTask(mono->motData[D2R],pCon,
"d2r",d2r);
if(status > 0) {
AddTaskToGroup(pServ->pTasker,status,mono->waitID);
}
status = StartDriveTask(mono->motData[D2L],pCon,
"d2l",d2l);
if(status > 0) {
AddTaskToGroup(pServ->pTasker,status,mono->waitID);
}
}
/*--------------------------------------------------------------*/
static void startA2W(peigerMono mono, SConnection *pCon)
{
float d2r, d2l, val;
int status;
GetDrivablePosition(mono->motData[A2ROT],pCon,&val);
if(val < -99999.99) {
SCWrite(pCon,"ERROR: failed to read a2rot",eError);
return;
}
mono->waitID = GetTaskGroupID(pServ->pTasker);
calcSlitTargets(mono,val,&d2r,&d2l);
status = StartDriveTask(mono->motData[D2R],pCon,
"d2r",d2r);
if(status > 0) {
AddTaskToGroup(pServ->pTasker,status,mono->waitID);
}
status = StartDriveTask(mono->motData[D2L],pCon,
"d2l",d2l);
if(status > 0) {
AddTaskToGroup(pServ->pTasker,status,mono->waitID);
}
}
/*----------------------------------------------------------------
Checks the status of a running motor. Possible return values
HWBusy The motor is still running
OKOK or HWIdle when the motor finished driving
HWFault when a hardware problem ocurred
HWPosFault when the hardware cannot reach a position
Errors are duly to be printed to pCon
For real motors CheckStatus again shall try hard to fix any
issues with the motor
------------------------------------------------------------------*/
static int EIMOCheckStatus(void *data, SConnection *pCon){
pSICSOBJ self = NULL;
float val;
self = (pSICSOBJ)data;
peigerMono mono = (peigerMono)self->pPrivate;
switch(mono->state){
case IDLE:
return HWIdle;
break;
case STARTMONO:
startMono(self,pCon);
mono->state = WAITING;
break;
case STARTA2:
startA2(mono,pCon);
mono->state = WAITING;
break;
case STARTA2W:
startA2W(mono,pCon);
mono->state = WAITING;
break;
case WAITING:
if(isTaskGroupRunning(pServ->pTasker, mono->waitID)){
return HWBusy;
} else {
mono->state = IDLE;
return HWIdle;
}
break;
case WAITA2:
/*
after a Halt, wait for A2 to finish, then drive the slits
into an open position
*/
if(isTaskGroupRunning(pServ->pTasker, mono->waitID)){
return HWBusy;
} else {
GetDrivablePosition(mono->motData[A2ROT], pCon, &val);
if(val > -99999.99){
mono->a2Target = val;
startA2W(mono,pCon);
}
mono->state = WAITING;
return HWBusy;
}
break;
default:
assert(1);
break;
}
return HWBusy;
}
/*----------------------------------------------------------------
GetValue is supposed to read a motor position
On errors, -99999999.99 is returned and messages printed to pCon
------------------------------------------------------------------*/
static float EIMOGetValue(void *data, SConnection *pCon){
pSICSOBJ self = NULL;
float val = -99999999.99;
self = (pSICSOBJ)data;
peigerMono mono = (peigerMono)self->pPrivate;
GetDrivablePosition(mono->motData[A2ROT],pCon,&val);
return val;
}
/*------------------------------------------------------------------*/
static float EIMOGetA2WValue(void *data, SConnection *pCon){
pSICSOBJ self = NULL;
float vall, valr;
double d2ro, d2lo, a2w;
self = (pSICSOBJ)data;
peigerMono mono = (peigerMono)self->pPrivate;
GetDrivablePosition(mono->motData[D2R],pCon,&valr);
GetDrivablePosition(mono->motData[D2L],pCon,&vall);
d2ro = RIGHTSIZE - mono->a2Target;
d2lo = LEFTSIZE + mono->a2Target;
a2w = (d2lo - vall) + (d2ro - valr);
return ABS(a2w);
}
/*----------------------------------------------------------------
returns NULL on failure, a new datastructure else
------------------------------------------------------------------*/
static pIDrivable EIMOMakeDrivable(){
pIDrivable pDriv;
pDriv = calloc(1,sizeof(IDrivable));
if(pDriv == NULL){
return NULL;
}
pDriv->Halt = EIMOHalt;
pDriv->CheckLimits = EIMOCheckLimits;
pDriv->SetValue = EIMOSetValue;
pDriv->CheckStatus = EIMOCheckStatus;
pDriv->GetValue = EIMOGetValue;
return pDriv;
}
/*======================================================
* The A2W Drivable
======================================================*/
typedef struct {
pObjectDescriptor pDes;
pIDrivable pDriv;
peigerMono eiger;
}EigerA2W, *eigera2w;
/*------------------------------------------------------*/
static void *eigera2wGetInterface(void *data, int iD){
eigera2w self = NULL;
self = (eigera2w)data;
if(self != NULL && iD == DRIVEID){
return self->pDriv;
} else {
return NULL;
}
return NULL;
}
/*---------------------------------------------------------------*/
static int eigera2wSaveStatus(void *data, char *name, FILE *fd)
{
eigera2w self = NULL;
self = (eigera2w)data;
fprintf(fd,"%s target %f\n", name, self->eiger->a2wTarget);
return 1;
}
/*----------------------------------------------------------------
returns NULL on failure, a new datastructure else
------------------------------------------------------------------*/
static eigera2w eigera2wMakeObject(peigerMono eiger){
eigera2w self = NULL;
self = malloc(sizeof(EigerA2W));
if(self == NULL){
return NULL;
}
memset(self,0,sizeof(EigerA2W));
self->pDes = CreateDescriptor("EigerA2W");
self->pDriv = CreateDrivableInterface();
if(self->pDes == NULL || self->pDriv == NULL){
return NULL;
}
self->eiger = eiger;
self->pDes->GetInterface = eigera2wGetInterface;
self->pDes->SaveStatus = eigera2wSaveStatus;
self->pDriv->Halt = EIMOHalt;
self->pDriv->CheckLimits = EIMOCheckLimits;
self->pDriv->SetValue = EIMOSetA2WValue;
self->pDriv->CheckStatus = EIMOCheckStatus;
self->pDriv->GetValue = EIMOGetA2WValue;
return self;
}
/*======================================================
* The A2 Drivable
======================================================*/
static void *eigera2GetInterface(void *data, int iD){
eigera2w self = NULL;
self = (eigera2w)data;
if(self != NULL && iD == DRIVEID){
return self->pDriv;
} else {
return NULL;
}
return NULL;
}
/*---------------------------------------------------------------*/
static int eigera2SaveStatus(void *data, char *name, FILE *fd)
{
eigera2w self = NULL;
self = (eigera2w)data;
fprintf(fd,"%s target %f\n", name, self->eiger->a2Target);
return 1;
}
/*----------------------------------------------------------------
returns NULL on failure, a new datastructure else
------------------------------------------------------------------*/
static eigera2w eigera2MakeObject(peigerMono eiger){
eigera2w self = NULL;
self = malloc(sizeof(EigerA2W));
if(self == NULL){
return NULL;
}
memset(self,0,sizeof(EigerA2W));
self->pDes = CreateDescriptor("EigerA2");
self->pDriv = CreateDrivableInterface();
if(self->pDes == NULL || self->pDriv == NULL){
return NULL;
}
self->eiger = eiger;
self->pDes->GetInterface = eigera2GetInterface;
self->pDes->SaveStatus = eigera2SaveStatus;
self->pDriv->Halt = EIMOHalt;
self->pDriv->CheckLimits = EIMOCheckLimits;
self->pDriv->SetValue = EIMOSetA2Value;
self->pDriv->CheckStatus = EIMOCheckStatus;
self->pDriv->GetValue = EIMOGetValue;
return self;
}
/*---------------------------------------------------------------*/
int EIMODrivableAction(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
pIDrivable pDriv = NULL;
pDummy pDum;
float value;
char pBuffer[132];
eigera2w self= NULL;
eigera2w selfe = NULL;
assert(pData != NULL);
if(argc > 1){
strtolower(argv[1]);
if(strcmp(argv[1],"target") == 0){
if(strcmp(argv[0],"a2w") == 0 && argc > 2){
self = (eigera2w)pData;
self->eiger->a2wTarget = atof(argv[2]);
SCSendOK(pCon);
return 1;
} else if (strcmp(argv[0],"a2") == 0 && argc > 2) {
selfe = (eigera2w)pData;
selfe->eiger->a2Target = atof(argv[2]);
SCSendOK(pCon);
return 1;
}
}
}
pDum = (pDummy)pData;
pDriv = (pIDrivable) pDum->pDescriptor->GetInterface(pDum,DRIVEID);
value = pDriv->GetValue(pDum, pCon);
if (value < -9000.) {
snprintf(pBuffer, 131, "ERROR: failed to read %s", argv[0]);
SCWrite(pCon, pBuffer, eError);
return 0;
}
snprintf(pBuffer, 131, "%s = %f", argv[0], value);
SCWrite(pCon, pBuffer, eValue);
return 1;
}
/*-------------------------------------------------------------------------*/
static int RegisterFunc(pSICSOBJ self, SConnection *pCon,
pHdb commandNode, pHdb par[], int nPar)
{
peigerMono eiger = (peigerMono)self->pPrivate;
ptasUB tas = NULL;
/*
install into TAS
*/
tas = (ptasUB)FindCommandData(pServ->pSics,"tasub",NULL);
if(!tas){
SCWrite(pCon,"ERROR: tasub module not found", eError);
return 0;
}
eiger->mono = &(tas->machine.monochromator);
eiger->tasub = tas;
tas->monoData = self;
tas->mono = EIMOMakeDrivable();
if(tas->mono == NULL){
SCWrite(pCon,"ERROR: error initializing EIGER monochromator, tasub now broken",
eError);
return 0;
}
return 1;
}
/*-------------------------------------------------------------------------*/
int InitEigerMono(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[])
{
pIDrivable pDriv = NULL;
eigera2w a2 = NULL;
eigera2w a2w = NULL;
pSICSOBJ pNew = NULL;
peigerMono eiger = NULL;
int i;
ptasUB tas = NULL;
pHdb cmd;
pNew = MakeSICSOBJ("emo","EigerMonochromator");
eiger = calloc(1,sizeof(eigerMono));
if(pNew == NULL || eiger == NULL){
SCWrite(pCon,"ERROR: out of memory creating Eiger Monochromator",eError);
return 0;
}
pNew->pPrivate = eiger;
cmd = AddSICSHdbPar(pNew->objectNode, "MTA", usMugger, MakeHdbFloat(.0));
SetHdbProperty(cmd,"__save","true");
cmd = AddSICSHdbPar(pNew->objectNode, "MTB", usMugger, MakeHdbFloat(3.7));
SetHdbProperty(cmd,"__save","true");
AddSICSHdbPar(pNew->objectNode, "register", usMugger,
MakeSICSFunc(RegisterFunc));
/*
get motors
*/
for(i = 0; i < 7; i++){
pDriv = FindDrivable(pSics,motNames[i]);
if(pDriv == NULL){
SCPrintf(pCon,eError,"ERROR: %s motor not found", motNames[i]);
return 0;
}
eiger->drivs[i] = pDriv;
eiger->motData[i] = FindCommandData(pSics,motNames[i],NULL);
}
/*
install into interpreter
*/
a2 = eigera2MakeObject(eiger);
a2w = eigera2wMakeObject(eiger);
if(a2 == NULL || a2w == NULL){
SCWrite(pCon,"ERROR: out of memory creating a2, a2w", eError);
return 0;
}
AddCommand(pSics, "a2", EIMODrivableAction, NULL, a2);
AddCommand(pSics, "a2w", EIMODrivableAction, NULL, a2w);
AddCommand(pSics,"emo", InterInvokeSICSOBJ, KillSICSOBJ, pNew);
return 1;
}

892
el734dc.c
View File

@ -1,892 +0,0 @@
/*-------------------------------------------------------------------------
A motor driver for EL734 DC motors as used at SinQ
Mark Koennecke, November 1996
Original code foe EL734 stepper, modified for DC motors, the
11-June-1997 Mark Koennecke
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 <stdlib.h>
#include <assert.h>
#include <string.h>
#include <fortify.h>
#include <sics.h>
#include "modriv.h"
#include "hardsup/sinq_prototypes.h"
#include "hardsup/rs232c_def.h"
#include "hardsup/el734_def.h"
#include "hardsup/el734fix.h"
#include <bit.h>
#include <splitter.h>
#include <servlog.h>
static int EL734EncodeMSR(char *text, int iLen,
int iMSR, int iOMSR, int iFP, int iFR);
static int EL734AnalyzeMSR(int iMSR, int iOMSR);
/* addional error codes for Status-things */
#define MSRBUSY -40
#define MSRONLIMIT -41
#define MSRRUNFAULT -42
#define MSRPOSFAULT -43
#define MSRDEADCUSHION -44
#define MSRHALT -45
#define MSRSTOP -46
#define MSROK -47
#define MSRREF -48
#define MSRFAULT -49
/*-----------------------------------------------------------------------
The motor driver structure. Please note that the first set of fields has
be identical with the fields of AbstractModriv in ../modriv.h
------------------------------------------------------------------------*/
typedef struct __MoDriv {
/* general motor driver interface
fields. REQUIRED!
*/
float fUpper; /* upper limit */
float fLower; /* lower limit */
char *name;
int (*GetPosition) (void *self, float *fPos);
int (*RunTo) (void *self, float fNewVal);
int (*GetStatus) (void *self);
void (*GetError) (void *self, int *iCode, char *buffer, int iBufLen);
int (*TryAndFixIt) (void *self, int iError, float fNew);
int (*Halt) (void *self);
int (*GetDriverPar) (void *self, char *name, float *value);
int (*SetDriverPar) (void *self, SConnection * pCon,
char *name, float newValue);
void (*ListDriverPar) (void *self, char *motorName, SConnection * pCon);
void (*KillPrivate) (void *self);
/* EL-734 specific fields */
int iPort;
char *hostname;
int iChannel;
int iMotor;
void *EL734struct;
int iMSR;
} EL734Driv;
/* --------------------------------------------------------------------------*/
static int GetPos(void *self, float *fData)
{
EL734Driv *pDriv;
float fPos;
int iRet, iMSR, iOMSR, iFRC, iFPC, iSS;
assert(self);
pDriv = (EL734Driv *) self;
iRet = EL734_GetStatus(&(pDriv->EL734struct),
&iMSR, &iOMSR, &iFPC, &iFRC, &iSS, &fPos);
if (iMSR != 0) {
pDriv->iMSR = iMSR;
}
*fData = fPos;
if (iRet != 1) {
return HWFault;
} else
return OKOK;
}
/*--------------------------------------------------------------------------*/
static int Run(void *self, float fNew)
{
EL734Driv *pDriv;
int iRet;
assert(self);
pDriv = (EL734Driv *) self;
iRet = EL734_MoveNoWait(&(pDriv->EL734struct), fNew);
if (iRet == 1) {
return OKOK;
} else {
return HWFault;
}
}
/*---------------------------------------------------------------------------
EL734Error2Text converts between an EL734 error code to text
-----------------------------------------------------------------------------*/
static void EL734Error2Text(char *pBuffer, int iErr)
{
strcpy(pBuffer, "ERROR: HW:");
switch (iErr) {
case EL734__BAD_ADR:
strcat(pBuffer, "EL734__BAD_ADR");
break;
case EL734__BAD_BIND:
strcat(pBuffer, "EL734__BAD_BIND");
break;
case EL734__BAD_CMD:
strcat(pBuffer, "EL734__BAD_CMD");
break;
case EL734__BAD_CONNECT:
strcat(pBuffer, "EL734__BAD_CONNECT");
break;
case EL734__BAD_FLUSH:
strcat(pBuffer, "EL734__BAD_FLUSH");
break;
case EL734__BAD_HOST:
strcat(pBuffer, "EL734__BAD_HOST");
break;
case EL734__BAD_ID:
strcat(pBuffer, "EL734__BAD_ID");
break;
case EL734__BAD_ILLG:
strcat(pBuffer, "EL734__BAD_ILLG");
break;
case EL734__BAD_LOC:
strcat(pBuffer, "EL734__BAD_LOC");
break;
case EL734__BAD_MALLOC:
strcat(pBuffer, "EL734__BAD_MALLOC");
break;
case EL734__BAD_NOT_BCD:
strcat(pBuffer, "EL734__BAD_NOT_BCD");
break;
case EL734__BAD_OFL:
strcat(pBuffer, "EL734__BAD_OFL");
break;
case EL734__BAD_PAR:
strcat(pBuffer, "EL734__BAD_PAR");
break;
case EL734__BAD_RECV:
strcat(pBuffer, "EL734__BAD_RECV");
break;
case EL734__BAD_RECV_NET:
strcat(pBuffer, "EL734__BAD_RECV_NET");
break;
case EL734__BAD_RECV_PIPE:
strcat(pBuffer, "EL734__BAD_RECV_PIPE");
break;
case EL734__BAD_RECV_UNKN:
strcat(pBuffer, "EL734__BAD_RECV_UNKN");
break;
case EL734__BAD_RECVLEN:
strcat(pBuffer, "EL734__BAD_RECVLEN");
break;
case EL734__BAD_RECV1:
strcat(pBuffer, "EL734__BAD_RECV1");
break;
case EL734__BAD_RECV1_NET:
strcat(pBuffer, "EL734__BAD_RECV1_NET");
break;
case EL734__BAD_RECV1_PIPE:
strcat(pBuffer, "EL734__BAD_RECV1_PIPE");
break;
case EL734__BAD_RNG:
strcat(pBuffer, "EL734__BAD_RNG");
break;
case EL734__BAD_SEND:
strcat(pBuffer, "EL734__BAD_SEND");
break;
case EL734__BAD_SEND_PIPE:
strcat(pBuffer, "EL734__BAD_SEND_PIPE");
break;
case EL734__BAD_SEND_NET:
strcat(pBuffer, "EL734__BAD_SEND_NET");
break;
case EL734__BAD_SEND_UNKN:
strcat(pBuffer, "EL734__BAD_SEND_UNKN");
break;
case EL734__BAD_SENDLEN:
strcat(pBuffer, "EL734__BAD_SENDLEN");
break;
case EL734__BAD_SOCKET:
strcat(pBuffer, "EL734__BAD_SOCKET");
break;
case EL734__BAD_TMO:
strcat(pBuffer, "EL734__BAD_TMO");
break;
case EL734__FORCED_CLOSED:
strcat(pBuffer, "EL734__FORCED_CLOSED");
break;
case EL734__BAD_STP:
strcat(pBuffer, "EL734__BAD_STP");
break;
case EL734__EMERG_STOP:
strcat(pBuffer, "EL734__EMERG_STOP");
break;
case EL734__NOT_OPEN:
strcat(pBuffer, "EL734__NOT_OPEN");
break;
case EL734__BAD_ASYNSRV:
strcat(pBuffer, "EL734__BAD_ASYNSRV");
break;
default:
sprintf(pBuffer, "Unknown EL734 error %d", iErr);
break;
}
}
/*-------------------------------------------------------------------------*/
static void GetErr(void *self, int *iCode, char *buffer, int iBufLen)
{
EL734Driv *pDriv;
char pBueffel[512];
int iMSR, iOMSR, iSS;
int iRet, iFPC, iFRC;
int iErr;
float fPos;
char *pErr;
assert(self);
/* get EL734 error codes */
pDriv = (EL734Driv *) self;
EL734_ErrInfo(&pErr, &iMSR, &iOMSR, &iSS);
if (iMSR != 0) {
EL734Error2Text(pBueffel, iMSR);
strlcpy(buffer, pBueffel, (iBufLen - 1));
*iCode = iMSR;
return;
} else { /* check status flag for addional errors */
iRet = EL734_GetStatus(&(pDriv->EL734struct),
&iMSR, &iOMSR, &iFPC, &iFRC, &iSS, &fPos);
if (iRet != 1) { /* failure on this one, this has to be handled */
EL734_ErrInfo(&pErr, &iMSR, &iOMSR, &iSS);
EL734Error2Text(pBueffel, iMSR);
strlcpy(buffer, pBueffel, (iBufLen - 1));
*iCode = iMSR;
return;
} else {
/* we really come down to looking at status flags */
*iCode = EL734EncodeMSR(buffer, iBufLen, iMSR, iOMSR, iFPC, iFRC);
}
}
}
/* ------------------------------------------------------------------------
Types of errors possible on EL734:
Network error: Try reopening connection and redo command.
Than there are problems which might have to do with a dodgy RS232,
resend command may help
Some things cannot be fixed.
*/
static int FixError(void *self, int iError, float fNew)
{
EL734Driv *pDriv;
int iRet;
char pBueffel[512];
int iMSR, iOMSR, iSS;
float fPos;
assert(self);
pDriv = (EL734Driv *) self;
sprintf(pBueffel, "EL734 : %s %d %d %d Problem:", pDriv->hostname,
pDriv->iPort, pDriv->iChannel, pDriv->iMotor);
/* get & check MSR flags */
/* check for codes */
switch (iError) {
case 0: /* no error at all */
return MOTOK;
case EL734__BAD_ID: /* ID */
case EL734__BAD_ADR: /* ADR */
case EL734__BAD_CMD: /* CMD */
case EL734__BAD_ILLG: /* ILLG */
case EL734__BAD_PAR: /* PAR */
case EL734__BAD_TMO:
SICSLogWrite(pBueffel, eHWError);
SICSLogWrite("BAD Command or dodgy RS-232", eHWError);
return MOTREDO;
case EL734__EMERG_STOP:
return MOTFAIL;
case EL734__BAD_RNG: /* RNG */
case MSRONLIMIT:
SICSLogWrite(pBueffel, eHWError);
SICSLogWrite("Out of Range", eHWError);
return MOTFAIL;
case EL734__BAD_STP:
return MOTFAIL;
break;
case MSRBUSY:
return MOTREDO;
case MSRRUNFAULT:
SICSLogWrite(pBueffel, eHWError);
SICSLogWrite("------ RUN Fault in Controller ---- ", eHWError);
return MOTFAIL;
case MSRPOSFAULT:
SICSLogWrite(pBueffel, eHWError);
SICSLogWrite("------ POS Fault in Controller ---- ", eHWError);
return MOTFAIL;
case MSRDEADCUSHION:
SICSLogWrite(pBueffel, eHWError);
SICSLogWrite("------ Air cushion Fault in Controller ---- ", eHWError);
return MOTFAIL;
case MSRFAULT:
return MOTFAIL;
case MSRHALT:
case MSRSTOP:
return MOTFAIL;
case EL734__FORCED_CLOSED:
case EL734__NOT_OPEN:
iRet = EL734_Open(&(pDriv->EL734struct), pDriv->hostname,
pDriv->iPort, pDriv->iChannel,
pDriv->iMotor, "DCMC EL734");
if (iRet != 1) {
return MOTFAIL;
} else {
return MOTREDO;
}
break;
case EL734__BAD_LOC: /* LO2 */
case EL734__BAD_OFL:
EL734_Close(&(pDriv->EL734struct), 0);
iRet = EL734_Open(&(pDriv->EL734struct), pDriv->hostname,
pDriv->iPort, pDriv->iChannel,
pDriv->iMotor, "DCMC EL734");
if (iRet != 1) {
return MOTFAIL;
} else {
return MOTREDO;
}
break;
/* case EL734__BAD_ASYNSRV:
EL734_Close(&(pDriv->EL734struct),1);
return MOTREDO;
break;
*/ default:
SICSLogWrite(pBueffel, eHWError);
SICSLogWrite("Network problem, trying to reopen", eHWError);
EL734_Close(&(pDriv->EL734struct), 1);
iRet = EL734_Open(&(pDriv->EL734struct), pDriv->hostname,
pDriv->iPort, pDriv->iChannel,
pDriv->iMotor, "DCMC EL734");
if (iRet != 1) {
return MOTFAIL;
} else {
return MOTREDO;
}
}
}
/*--------------------------------------------------------------------------*/
static int Halt(void *self)
{
EL734Driv *pDriv;
int iRet;
char pBueffel[80];
assert(self);
pDriv = (EL734Driv *) self;
iRet = EL734_Stop(&(pDriv->EL734struct));
if (iRet != 1) {
return OKOK;
}
return HWFault;
}
/*--------------------------------------------------------------------------*/
static int GetStat(void *self)
{
EL734Driv *pDriv;
float fPos;
int iRet, iMSR, iOMSR, iFRC, iFPC, iSS;
int eRet;
int iTest;
char pBueffel[80];
assert(self);
pDriv = (EL734Driv *) self;
iRet = EL734_GetStatus(&(pDriv->EL734struct),
&iMSR, &iOMSR, &iFPC, &iFRC, &iSS, &fPos);
if (iRet != 1) {
return HWFault;
}
if (iMSR != 0) {
pDriv->iMSR = iMSR;
}
iTest = EL734AnalyzeMSR(iMSR, iOMSR);
switch (iTest) {
case MSRDEADCUSHION:
case MSRONLIMIT:
case MSRREF:
case MSRHALT:
case MSRSTOP:
return HWFault;
break;
case MSRRUNFAULT:
case MSRPOSFAULT:
return HWPosFault;
break;
case MSRBUSY:
return HWBusy;
break;
case MSRFAULT:
return HWWarn;
break;
default:
return HWIdle;
break;
}
}
/*--------------------------------------------------------------------------*/
extern void KillEL734(void *pdata); /* from el734driv.c */
/*---------------------------------------------------------------------------*/
static EL734Driv *MakeEL734DC(char *hostname, int iPort, int iChannel,
int iMotor)
{
EL734Driv *pDriv = NULL;
int iError;
char pBueffel[80];
char *pErr;
int iRet;
int iDummy;
/* create a new struct */
pDriv = (EL734Driv *) malloc(sizeof(EL734Driv));
if (!pDriv) {
return NULL;
}
memset(pDriv, 0, sizeof(EL734Driv));
/* fill in some of the data entered */
pDriv->hostname = strdup(hostname);
pDriv->iPort = iPort;
pDriv->iChannel = iChannel;
pDriv->iMotor = iMotor;
pDriv->name = strdup("EL734");
/* try opening the motor */
iRet = EL734_Open(&(pDriv->EL734struct), hostname, iPort,
iChannel, iMotor, "DCMC EL734");
if (iRet != 1) {
EL734_ErrInfo(&pErr, &iError, &iRet, &iDummy);
KillEL734((void *) pDriv);
return NULL;
}
/* now get the limits */
EL734_GetLimits(&(pDriv->EL734struct), &(pDriv->fLower),
&(pDriv->fUpper));
/* initialise the function pointers */
pDriv->GetPosition = GetPos;
pDriv->RunTo = Run;
pDriv->GetError = GetErr;
pDriv->GetStatus = GetStat;
pDriv->Halt = Halt;
pDriv->TryAndFixIt = FixError;
pDriv->KillPrivate = KillEL734;
return pDriv;
}
/*--------------------------------------------------------------------------
interpreting the driver parameters is up to the driver, this below
inplements just this
*/
MotorDriver *CreateEL734DC(SConnection * pCon, int argc, char *argv[])
{
EL734Driv *pDriv = NULL;
TokenList *pList = NULL;
TokenList *pCurrent;
char *hostname;
int iPort, iChannel, iMotor;
char pBueffel[512];
assert(pCon);
/* split arguments */
pList = SplitArguments(argc, argv);
if (!pList) {
SCWrite(pCon, "Error parsing arguments", eError);
return NULL;
}
/* first must be hostname */
pCurrent = pList;
if (pCurrent->Type != eText) {
sprintf(pBueffel, "EL734DC: Expected hostname but got --> %s <--",
pCurrent->text);
SCWrite(pCon, pBueffel, eError);
DeleteTokenList(pList);
return NULL;
}
hostname = pCurrent->text;
/* next should be port */
pCurrent = pCurrent->pNext;
if (!pCurrent) {
SCWrite(pCon, "EL734DC: Insufficient number of arguments", eError);
DeleteTokenList(pList);
return NULL;
}
if (pCurrent->Type != eInt) {
sprintf(pBueffel,
"EL734DC: Expected Integer as Port number, got --> %s <--",
pCurrent->text);
SCWrite(pCon, pBueffel, eError);
DeleteTokenList(pList);
return NULL;
}
iPort = pCurrent->iVal;
/* next should be Channel number */
pCurrent = pCurrent->pNext;
if (!pCurrent) {
SCWrite(pCon, "EL734DC: Insufficient number of arguments", eError);
DeleteTokenList(pList);
return NULL;
}
if (pCurrent->Type != eInt) {
sprintf(pBueffel,
"EL734DC: Expected Integer as channel number, got --> %s <--",
pCurrent->text);
SCWrite(pCon, pBueffel, eError);
DeleteTokenList(pList);
return NULL;
}
iChannel = pCurrent->iVal;
/* finally motor number */
pCurrent = pCurrent->pNext;
if (!pCurrent) {
SCWrite(pCon, "EL734DC: Insufficient number of arguments", eError);
DeleteTokenList(pList);
return NULL;
}
if (pCurrent->Type != eInt) {
sprintf(pBueffel,
"EL734DC: Expected Integer as motor number, got --> %s <--",
pCurrent->text);
SCWrite(pCon, pBueffel, eError);
DeleteTokenList(pList);
return NULL;
}
iMotor = pCurrent->iVal;
/* finally initialize driver */
pDriv = MakeEL734DC(hostname, iPort, iChannel, iMotor);
if (!pDriv) {
SCWrite(pCon, "EL734DC: error opening motor, check adress", eError);
pDriv = NULL;
}
/* clean up */
DeleteTokenList(pList);
return (MotorDriver *) pDriv;
}
/*-------------------------------------------------------------------------
Stolen from David and modified to return an integer error code as well
*/
static int EL734EncodeMSR(char *text, int text_len,
int msr, int ored_msr, int fp_cntr, int fr_cntr)
{
int len;
char my_text[132];
char my_text_0[32];
int iRet = 0;
if (msr == 0) {
ored_msr = ored_msr & ~(MSR__BUSY); /* Zero "Busy" bit */
if (ored_msr == MSR__OK) {
StrJoin(text, text_len, "Status, MSR = Idle. Positioned OK.", "");
} else {
if ((ored_msr & MSR__OK) != 0) {
StrJoin(text, text_len, "Status, MSR = Idle. Positioned OK. ", "");
} else {
StrJoin(text, text_len, "Status, MSR = Idle. ", "");
}
if ((ored_msr & MSR__REF_OK) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Ref. Pos'n OK. ");
}
if ((ored_msr & MSR__LIM_ERR) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Limit Switch Problem. ");
iRet = MSRONLIMIT;
}
if ((ored_msr & MSR__AC_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Air-Cushion Error. ");
iRet = MSRDEADCUSHION;
}
if ((ored_msr & MSR__REF_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Ref. Pos'n Fail. ");
}
if ((ored_msr & MSR__POS_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Pos'n Fail. ");
iRet = MSRPOSFAULT;
}
if ((ored_msr & MSR__POS_FAULT) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
if (fp_cntr == 1) {
StrJoin(text, text_len, my_text, "1 Pos'n Fault. ");
} else {
sprintf(my_text_0, "%d Pos'n Faults. ", fp_cntr);
StrJoin(text, text_len, my_text, my_text_0);
}
}
if ((ored_msr & MSR__RUN_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Run Fail. ");
iRet = MSRRUNFAULT;
}
if ((ored_msr & MSR__RUN_FAULT) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
if (fr_cntr == 1) {
StrJoin(text, text_len, my_text, "1 Run Fault. ");
} else {
sprintf(my_text_0, "%d Run Faults. ", fr_cntr);
StrJoin(text, text_len, my_text, my_text_0);
}
}
if ((ored_msr & MSR__HALT) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Halt. ");
iRet = MSRHALT;
}
if ((ored_msr & MSR__HI_LIM) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Hit HiLim. ");
iRet = MSRONLIMIT;
}
if ((ored_msr & MSR__LO_LIM) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Hit LoLim. ");
iRet = MSRONLIMIT;
}
if ((ored_msr & MSR__STOPPED) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Stopped. ");
iRet = MSRSTOP;
}
}
} else if ((msr & ~(0x2fff)) != 0) {
StrJoin(text, text_len, "Status, MSR = ??", "");
} else {
sprintf(my_text, "%#x ", msr);
StrJoin(text, text_len, "Status, MSR = ", my_text);
if ((msr & MSR__LIM_ERR) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Limit Switch Problem/");
iRet = MSRONLIMIT;
}
if ((msr & MSR__AC_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Air-Cushion Error/");
iRet = MSRDEADCUSHION;
}
if ((msr & MSR__REF_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Ref. Pos'n Fail/");
}
if ((msr & MSR__POS_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Pos'n Fail/");
iRet = MSRPOSFAULT;
}
if ((msr & MSR__POS_FAULT) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Pos'n Fault/");
}
if ((msr & MSR__RUN_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Run Fail/");
iRet = MSRRUNFAULT;
}
if ((msr & MSR__RUN_FAULT) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Run Fault/");
}
if ((msr & MSR__HALT) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Halt/");
iRet = MSRHALT;
}
if ((msr & MSR__HI_LIM) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Hit HiLim/");
iRet = MSRONLIMIT;
}
if ((msr & MSR__LO_LIM) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Hit LoLim/");
iRet = MSRONLIMIT;
}
if ((msr & MSR__STOPPED) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Stopped/");
iRet = MSRSTOP;
}
if ((msr & MSR__REF_OK) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Ref. Pos'n OK/");
}
if ((msr & MSR__OK) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "OK/");
}
if ((msr & MSR__BUSY) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Busy/");
}
len = strlen(text);
text[len - 1] = '\0';
}
return iRet;
}
/*-------------------------------------------------------------------------*/
static int EL734AnalyzeMSR(int msr, int ored_msr)
{
int iRet = 0;
/* this means the motor is done */
if (msr == 0) {
ored_msr = ored_msr & ~(MSR__BUSY); /* Zero "Busy" bit */
if (ored_msr == MSR__OK) {
iRet = MSROK;
} else {
if ((ored_msr & MSR__OK) != 0) {
iRet = MSROK;
} else {
iRet = MSROK;
}
if ((ored_msr & MSR__REF_OK) != 0) {
iRet = MSROK;
}
if ((ored_msr & MSR__LIM_ERR) != 0) {
return MSRONLIMIT;
}
if ((ored_msr & MSR__AC_FAIL) != 0) {
return MSRDEADCUSHION;
}
if ((ored_msr & MSR__REF_FAIL) != 0) {
iRet = MSRREF;
}
if ((ored_msr & MSR__POS_FAIL) != 0) {
return MSRPOSFAULT;
}
if ((ored_msr & MSR__POS_FAULT) != 0) {
iRet = MSRFAULT;
}
if ((ored_msr & MSR__RUN_FAIL) != 0) {
return MSRRUNFAULT;
}
if ((ored_msr & MSR__RUN_FAULT) != 0) {
iRet = MSRFAULT;
}
if ((ored_msr & MSR__HALT) != 0) {
return MSRHALT;
}
if ((ored_msr & MSR__HI_LIM) != 0) {
return MSRONLIMIT;
}
if ((ored_msr & MSR__LO_LIM) != 0) {
return MSRONLIMIT;
}
if ((ored_msr & MSR__STOPPED) != 0) {
return MSRSTOP;
}
}
/* the motor is still fighting along */
} else if ((msr & ~(0x2fff)) != 0) {
iRet = MSROK;
} else {
if ((msr & MSR__LIM_ERR) != 0) {
return MSRONLIMIT;
}
if ((msr & MSR__AC_FAIL) != 0) {
return MSRDEADCUSHION;
}
if ((msr & MSR__REF_FAIL) != 0) {
iRet = MSRREF;
}
if ((msr & MSR__POS_FAIL) != 0) {
return MSRPOSFAULT;
}
if ((msr & MSR__POS_FAULT) != 0) {
iRet = MSRFAULT;
}
if ((msr & MSR__RUN_FAIL) != 0) {
return MSRRUNFAULT;
}
if ((msr & MSR__RUN_FAULT) != 0) {
iRet = MSRFAULT;
}
if ((msr & MSR__HALT) != 0) {
return MSRHALT;
}
if ((msr & MSR__HI_LIM) != 0) {
return MSRONLIMIT;
}
if ((msr & MSR__LO_LIM) != 0) {
return MSRONLIMIT;
}
if ((msr & MSR__STOPPED) != 0) {
return MSRSTOP;
}
if ((msr & MSR__REF_OK) != 0) {
iRet = MSROK;
}
if ((msr & MSR__OK) != 0) {
iRet = MSROK;
}
if ((msr & MSR__BUSY) != 0) {
iRet = MSRBUSY;
}
}
return iRet;
}

View File

@ -1,905 +0,0 @@
/*--------------------------------------------------------------------------
A motor driver for EL734 type motors as used at SinQ
Mark Koennecke, November 1996
modified for new directory structure, June 2003, Mark Koennecke
Copyright:
Labor fuer Neutrnenstreuung
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 <stdlib.h>
#include <assert.h>
#include <string.h>
#include <fortify.h>
#include <sics.h>
#include <modriv.h>
#include "hardsup/sinq_prototypes.h"
#include "hardsup/rs232c_def.h"
#include "hardsup/el734_def.h"
#include "hardsup/el734fix.h"
#include <bit.h>
#include <splitter.h>
/*-----------------------------------------------------------------------
The motor driver structure. Please note that the first set of fields has
be identical with the fields of AbstractModriv in ../modriv.h
------------------------------------------------------------------------*/
typedef struct __MoDriv {
/* general motor driver interface
fields. REQUIRED!
*/
float fUpper; /* upper limit */
float fLower; /* lower limit */
char *name;
int (*GetPosition) (void *self, float *fPos);
int (*RunTo) (void *self, float fNewVal);
int (*GetStatus) (void *self);
void (*GetError) (void *self, int *iCode, char *buffer, int iBufLen);
int (*TryAndFixIt) (void *self, int iError, float fNew);
int (*Halt) (void *self);
int (*GetDriverPar) (void *self, char *name, float *value);
int (*SetDriverPar) (void *self, SConnection * pCon,
char *name, float newValue);
void (*ListDriverPar) (void *self, char *motorName, SConnection * pCon);
void (*KillPrivate) (void *self);
/* EL-734 specific fields */
int iPort;
char *hostname;
int iChannel;
int iMotor;
void *EL734struct;
int iMSR;
} EL734Driv;
static int EL734EncodeMSR(char *text, int iLen,
int iMSR, int iOMSR, int iFP, int iFR);
static int EL734AnalyzeMSR(int iMSR, int iOMSR);
/* addional error codes for Status-things */
#define MSRBUSY -40
#define MSRONLIMIT -41
#define MSRRUNFAULT -42
#define MSRPOSFAULT -43
#define MSRDEADCUSHION -44
#define MSRHALT -45
#define MSRSTOP -46
#define MSROK -47
#define MSRREF -48
#define MSRFAULT -49
/* --------------------------------------------------------------------------*/
static int GetPos(void *self, float *fData)
{
EL734Driv *pDriv;
float fPos;
int iRet, iMSR, iOMSR, iFRC, iFPC, iSS;
assert(self);
pDriv = (EL734Driv *) self;
iRet = EL734_GetStatus(&(pDriv->EL734struct),
&iMSR, &iOMSR, &iFPC, &iFRC, &iSS, &fPos);
if (iMSR != 0) {
pDriv->iMSR = iMSR;
}
*fData = fPos;
if (iRet != 1) {
return HWFault;
} else
return OKOK;
}
/*--------------------------------------------------------------------------*/
static int Run(void *self, float fNew)
{
EL734Driv *pDriv;
int iRet;
assert(self);
pDriv = (EL734Driv *) self;
iRet = EL734_MoveNoWait(&(pDriv->EL734struct), fNew);
if (iRet == 1) {
return OKOK;
} else {
return HWFault;
}
}
/*---------------------------------------------------------------------------
EL734Error2Text converts between an EL734 error code to text
-----------------------------------------------------------------------------*/
extern char EL734_IllgText[256];
static void EL734Error2Text(char *pBuffer, int iErr)
{
strcpy(pBuffer, "ERROR: HW:");
switch (iErr) {
case EL734__BAD_ADR:
strcat(pBuffer, "EL734__BAD_ADR");
break;
case EL734__BAD_BIND:
strcat(pBuffer, "EL734__BAD_BIND");
break;
case EL734__BAD_CMD:
strcat(pBuffer, "EL734__BAD_CMD");
break;
case EL734__BAD_CONNECT:
strcat(pBuffer, "EL734__BAD_CONNECT");
break;
case EL734__BAD_FLUSH:
strcat(pBuffer, "EL734__BAD_FLUSH");
break;
case EL734__BAD_HOST:
strcat(pBuffer, "EL734__BAD_HOST");
break;
case EL734__BAD_ID:
strcat(pBuffer, "EL734__BAD_ID");
break;
case EL734__BAD_ILLG:
strcat(pBuffer, "EL734__BAD_ILLG ");
strcat(pBuffer, EL734_IllgText);
break;
case EL734__BAD_LOC:
strcat(pBuffer, "EL734__BAD_LOC");
break;
case EL734__BAD_MALLOC:
strcat(pBuffer, "EL734__BAD_MALLOC");
break;
case EL734__BAD_NOT_BCD:
strcat(pBuffer, "EL734__BAD_NOT_BCD");
break;
case EL734__BAD_OFL:
strcat(pBuffer, "EL734__BAD_OFL");
break;
case EL734__BAD_PAR:
strcat(pBuffer, "EL734__BAD_PAR");
break;
case EL734__BAD_RECV:
strcat(pBuffer, "EL734__BAD_RECV");
break;
case EL734__BAD_RECV_NET:
strcat(pBuffer, "EL734__BAD_RECV_NET");
break;
case EL734__BAD_RECV_PIPE:
strcat(pBuffer, "EL734__BAD_RECV_PIPE");
break;
case EL734__BAD_RECV_UNKN:
strcat(pBuffer, "EL734__BAD_RECV_UNKN");
break;
case EL734__BAD_RECVLEN:
strcat(pBuffer, "EL734__BAD_RECVLEN");
break;
case EL734__BAD_RECV1:
strcat(pBuffer, "EL734__BAD_RECV1");
break;
case EL734__BAD_RECV1_NET:
strcat(pBuffer, "EL734__BAD_RECV1_NET");
break;
case EL734__BAD_RECV1_PIPE:
strcat(pBuffer, "EL734__BAD_RECV1_PIPE");
break;
case EL734__BAD_RNG:
strcat(pBuffer, "EL734__BAD_RNG");
break;
case EL734__BAD_SEND:
strcat(pBuffer, "EL734__BAD_SEND");
break;
case EL734__BAD_SEND_PIPE:
strcat(pBuffer, "EL734__BAD_SEND_PIPE");
break;
case EL734__BAD_SEND_NET:
strcat(pBuffer, "EL734__BAD_SEND_NET");
break;
case EL734__BAD_SEND_UNKN:
strcat(pBuffer, "EL734__BAD_SEND_UNKN");
break;
case EL734__BAD_SENDLEN:
strcat(pBuffer, "EL734__BAD_SENDLEN");
break;
case EL734__BAD_SOCKET:
strcat(pBuffer, "EL734__BAD_SOCKET");
break;
case EL734__BAD_TMO:
strcat(pBuffer, "EL734__BAD_TMO");
break;
case EL734__FORCED_CLOSED:
strcat(pBuffer, "EL734__FORCED_CLOSED");
break;
case EL734__BAD_STP:
strcat(pBuffer, "The motor is switched off at the motor controller");
break;
case EL734__EMERG_STOP:
strcat(pBuffer, "Emergency stop button depressed, please release");
break;
case EL734__NOT_OPEN:
strcat(pBuffer, "EL734__NOT_OPEN");
break;
case EL734__BAD_ASYNSRV:
strcat(pBuffer, "EL734__BAD_ASYNSRV");
break;
default:
sprintf(pBuffer, "Unknown EL734 error %d", iErr);
break;
}
}
/*-------------------------------------------------------------------------*/
static void GetErr(void *self, int *iCode, char *buffer, int iBufLen)
{
EL734Driv *pDriv;
char pBueffel[512];
int iMSR, iOMSR, iSS;
int iRet, iFPC, iFRC;
int iErr;
float fPos;
char *pErr;
assert(self);
/* get EL734 error codes */
pDriv = (EL734Driv *) self;
EL734_ErrInfo(&pErr, &iMSR, &iOMSR, &iSS);
if (iMSR != 0) {
EL734Error2Text(pBueffel, iMSR);
strlcpy(buffer, pBueffel, (iBufLen - 1));
*iCode = iMSR;
return;
} else { /* check status flag for addional errors */
iRet = EL734_GetStatus(&(pDriv->EL734struct),
&iMSR, &iOMSR, &iFPC, &iFRC, &iSS, &fPos);
if (iRet != 1) { /* failure on this one, this has to be handled */
EL734_ErrInfo(&pErr, &iMSR, &iOMSR, &iSS);
EL734Error2Text(pBueffel, iMSR);
strlcpy(buffer, pBueffel, (iBufLen - 1));
*iCode = iMSR;
return;
} else {
/* we really come down to looking at status flags */
*iCode = EL734EncodeMSR(buffer, iBufLen, iMSR, iOMSR, iFPC, iFRC);
}
}
}
/* ------------------------------------------------------------------------
Types of errors possible on EL734:
Network error: Try reopening connection and redo command.
Than there are problems which might have to do with a dodgy RS232,
resend command may help
Some things cannot be fixed.
*/
static int FixError(void *self, int iError, float fNew)
{
EL734Driv *pDriv;
int iRet;
char pBueffel[512];
int iMSR, iOMSR, iSS;
float fPos;
assert(self);
pDriv = (EL734Driv *) self;
sprintf(pBueffel, "EL734 : %s %d %d %d Problem:", pDriv->hostname,
pDriv->iPort, pDriv->iChannel, pDriv->iMotor);
/* get & check MSR flags */
/* check for codes */
switch (iError) {
case 0: /* no error at all */
return MOTOK;
case EL734__BAD_ID: /* ID */
case EL734__BAD_ADR: /* ADR */
case EL734__BAD_CMD: /* CMD */
case EL734__BAD_ILLG: /* ILLG */
case EL734__BAD_PAR: /* PAR */
case EL734__BAD_TMO: /* timeout */
SICSLogWrite(pBueffel, eHWError);
SICSLogWrite("BAD Command or dodgy RS-232", eHWError);
return MOTREDO;
case EL734__EMERG_STOP:
return MOTFAIL;
case EL734__BAD_STP: /* motor disabled by switch */
return MOTFAIL;
break;
case EL734__BAD_RNG: /* RNG */
case MSRONLIMIT:
SICSLogWrite(pBueffel, eHWError);
SICSLogWrite("Out of Range", eHWError);
return MOTFAIL;
case MSRBUSY:
return MOTREDO;
case MSRRUNFAULT:
SICSLogWrite(pBueffel, eHWError);
SICSLogWrite("------ RUN Fault in Controller ---- ", eHWError);
return MOTFAIL;
case MSRPOSFAULT:
SICSLogWrite(pBueffel, eHWError);
SICSLogWrite("------ POS Fault in Controller ---- ", eHWError);
return MOTFAIL;
case MSRDEADCUSHION:
SICSLogWrite(pBueffel, eHWError);
SICSLogWrite("------ Air cushion Fault in Controller ---- ", eHWError);
return MOTFAIL;
case MSRFAULT:
return MOTFAIL;
case MSRHALT:
case MSRSTOP:
return MOTFAIL;
case EL734__FORCED_CLOSED:
case EL734__NOT_OPEN:
iRet = EL734_Open(&(pDriv->EL734struct), pDriv->hostname,
pDriv->iPort, pDriv->iChannel,
pDriv->iMotor, "STPMC EL734");
if (iRet != 1) {
return MOTFAIL;
} else {
return MOTREDO;
}
break;
case EL734__BAD_OFL:
case EL734__BAD_LOC: /* LOocal mode */
EL734_Close(&(pDriv->EL734struct), 0);
iRet = EL734_Open(&(pDriv->EL734struct), pDriv->hostname,
pDriv->iPort, pDriv->iChannel,
pDriv->iMotor, "STPMC EL734");
if (iRet != 1) {
return MOTFAIL;
} else {
return MOTREDO;
}
break;
/* case EL734__BAD_ASYNSRV:
EL734_Close(&(pDriv->EL734struct),1);
return MOTREDO;
*/
default:
SICSLogWrite(pBueffel, eHWError);
SICSLogWrite("Network problem, trying to reopen", eHWError);
EL734_Close(&(pDriv->EL734struct), 1);
iRet = EL734_Open(&(pDriv->EL734struct), pDriv->hostname,
pDriv->iPort, pDriv->iChannel,
pDriv->iMotor, "STPMC EL734");
if (iRet != 1) {
return MOTFAIL;
} else {
return MOTREDO;
}
}
}
/*--------------------------------------------------------------------------*/
static int Halt(void *self)
{
EL734Driv *pDriv;
int iRet;
char pBueffel[80];
assert(self);
pDriv = (EL734Driv *) self;
iRet = EL734_Stop(&(pDriv->EL734struct));
if (iRet == 1) {
return OKOK;
}
return HWFault;
}
/*--------------------------------------------------------------------------*/
static int GetStat(void *self)
{
EL734Driv *pDriv;
float fPos;
int iRet, iMSR, iOMSR, iFRC, iFPC, iSS;
int eRet;
int iTest;
char pBueffel[80];
assert(self);
pDriv = (EL734Driv *) self;
iRet = EL734_GetStatus(&(pDriv->EL734struct),
&iMSR, &iOMSR, &iFPC, &iFRC, &iSS, &fPos);
if (iRet != 1) {
return HWFault;
}
if (iMSR != 0) {
pDriv->iMSR = iMSR;
}
iTest = EL734AnalyzeMSR(iMSR, iOMSR);
switch (iTest) {
case MSRDEADCUSHION:
case MSRONLIMIT:
case MSRREF:
case MSRHALT:
case MSRSTOP:
return HWFault;
break;
case MSRRUNFAULT:
case MSRPOSFAULT:
return HWPosFault;
break;
case MSRBUSY:
return HWBusy;
break;
case MSRFAULT:
return HWWarn;
break;
default:
return HWIdle;
break;
}
}
/*--------------------------------------------------------------------------*/
void KillEL734(void *self)
{
EL734Driv *pDriv;
assert(self);
pDriv = (EL734Driv *) self;
EL734_Close(&(pDriv->EL734struct), 0);
if (pDriv->hostname)
free(pDriv->hostname);
}
/*---------------------------------------------------------------------------*/
static EL734Driv *MakeEL734(char *hostname, int iPort, int iChannel,
int iMotor)
{
EL734Driv *pDriv = NULL;
int iError;
char pBueffel[80];
char *pErr;
int iRet;
int iDummy;
/* create a new struct */
pDriv = (EL734Driv *) malloc(sizeof(EL734Driv));
if (!pDriv) {
return NULL;
}
memset(pDriv, 0, sizeof(EL734Driv));
/* fill in some of the data entered */
pDriv->hostname = strdup(hostname);
pDriv->iPort = iPort;
pDriv->iChannel = iChannel;
pDriv->iMotor = iMotor;
pDriv->name = strdup("EL734");
/* try opening the motor */
iRet = EL734_Open(&(pDriv->EL734struct), hostname, iPort,
iChannel, iMotor, "STPMC EL734");
if (iRet != 1) {
EL734_ErrInfo(&pErr, &iError, &iRet, &iDummy);
KillEL734((void *) pDriv);
return NULL;
}
/* now get the limits */
EL734_GetLimits(&(pDriv->EL734struct), &(pDriv->fLower),
&(pDriv->fUpper));
/* initialise the function pointers */
pDriv->GetPosition = GetPos;
pDriv->RunTo = Run;
pDriv->GetError = GetErr;
pDriv->GetStatus = GetStat;
pDriv->Halt = Halt;
pDriv->TryAndFixIt = FixError;
pDriv->KillPrivate = KillEL734;
return pDriv;
}
/*--------------------------------------------------------------------------
interpreting the driver parameters is up to the driver, this below
inplements just this
*/
MotorDriver *CreateEL734(SConnection * pCon, int argc, char *argv[])
{
EL734Driv *pDriv = NULL;
TokenList *pList = NULL;
TokenList *pCurrent;
char *hostname;
int iPort, iChannel, iMotor;
char pBueffel[512];
assert(pCon);
/* split arguments */
pList = SplitArguments(argc, argv);
if (!pList) {
SCWrite(pCon, "Error parsing arguments", eError);
return NULL;
}
/* first must be hostname */
pCurrent = pList;
if (pCurrent->Type != eText) {
sprintf(pBueffel, "EL734: Expected hostname but got --> %s <--",
pCurrent->text);
SCWrite(pCon, pBueffel, eError);
DeleteTokenList(pList);
return NULL;
}
hostname = pCurrent->text;
/* next should be port */
pCurrent = pCurrent->pNext;
if (!pCurrent) {
SCWrite(pCon, "EL734: Insufficient number of arguments", eError);
DeleteTokenList(pList);
return NULL;
}
if (pCurrent->Type != eInt) {
sprintf(pBueffel,
"EL734: Expected Integer as Port number, got --> %s <--",
pCurrent->text);
SCWrite(pCon, pBueffel, eError);
DeleteTokenList(pList);
return NULL;
}
iPort = pCurrent->iVal;
/* next should be Channel number */
pCurrent = pCurrent->pNext;
if (!pCurrent) {
SCWrite(pCon, "EL734: Insufficient number of arguments", eError);
DeleteTokenList(pList);
return NULL;
}
if (pCurrent->Type != eInt) {
sprintf(pBueffel,
"EL734: Expected Integer as channel number, got --> %s <--",
pCurrent->text);
SCWrite(pCon, pBueffel, eError);
DeleteTokenList(pList);
return NULL;
}
iChannel = pCurrent->iVal;
/* finally motor number */
pCurrent = pCurrent->pNext;
if (!pCurrent) {
SCWrite(pCon, "EL734: Insufficient number of arguments", eError);
DeleteTokenList(pList);
return NULL;
}
if (pCurrent->Type != eInt) {
sprintf(pBueffel,
"EL734: Expected Integer as motor number, got --> %s <--",
pCurrent->text);
SCWrite(pCon, pBueffel, eError);
DeleteTokenList(pList);
return NULL;
}
iMotor = pCurrent->iVal;
/* finally initialize driver */
pDriv = MakeEL734(hostname, iPort, iChannel, iMotor);
if (!pDriv) {
SCWrite(pCon, "EL734: error opening motor, check adress", eError);
pDriv = NULL;
}
/* clean up */
DeleteTokenList(pList);
return (MotorDriver *) pDriv;
}
/*-------------------------------------------------------------------------
Stolen from David and modified to return an integer error code as well
*/
static int EL734EncodeMSR(char *text, int text_len,
int msr, int ored_msr, int fp_cntr, int fr_cntr)
{
int len;
char my_text[132];
char my_text_0[32];
int iRet = 0;
if (msr == 0) {
ored_msr = ored_msr & ~(MSR__BUSY); /* Zero "Busy" bit */
if (ored_msr == MSR__OK) {
StrJoin(text, text_len, "Status, MSR = Idle. Positioned OK.", "");
} else {
if ((ored_msr & MSR__OK) != 0) {
StrJoin(text, text_len, "Status, MSR = Idle. Positioned OK. ", "");
} else {
StrJoin(text, text_len, "Status, MSR = Idle. ", "");
}
if ((ored_msr & MSR__REF_OK) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Ref. Pos'n OK. ");
}
if ((ored_msr & MSR__LIM_ERR) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Limit Switch Problem. ");
iRet = MSRONLIMIT;
}
if ((ored_msr & MSR__AC_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Air-Cushion Error. ");
iRet = MSRDEADCUSHION;
}
if ((ored_msr & MSR__REF_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Ref. Pos'n Fail. ");
}
if ((ored_msr & MSR__POS_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Pos'n Fail. ");
iRet = MSRPOSFAULT;
}
if ((ored_msr & MSR__POS_FAULT) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
if (fp_cntr == 1) {
StrJoin(text, text_len, my_text, "1 Pos'n Fault. ");
} else {
sprintf(my_text_0, "%d Pos'n Faults. ", fp_cntr);
StrJoin(text, text_len, my_text, my_text_0);
}
}
if ((ored_msr & MSR__RUN_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Run Fail. ");
iRet = MSRRUNFAULT;
}
if ((ored_msr & MSR__RUN_FAULT) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
if (fr_cntr == 1) {
StrJoin(text, text_len, my_text, "1 Run Fault. ");
} else {
sprintf(my_text_0, "%d Run Faults. ", fr_cntr);
StrJoin(text, text_len, my_text, my_text_0);
}
}
if ((ored_msr & MSR__HALT) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Halt. ");
iRet = MSRHALT;
}
if ((ored_msr & MSR__HI_LIM) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Hit HiLim. ");
iRet = MSRONLIMIT;
}
if ((ored_msr & MSR__LO_LIM) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Hit LoLim. ");
iRet = MSRONLIMIT;
}
if ((ored_msr & MSR__STOPPED) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Stopped. ");
iRet = MSRSTOP;
}
}
} else if ((msr & ~(0x2fff)) != 0) {
StrJoin(text, text_len, "Status, MSR = ??", "");
} else {
sprintf(my_text, "%#x ", msr);
StrJoin(text, text_len, "Status, MSR = ", my_text);
if ((msr & MSR__LIM_ERR) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Limit Switch Problem/");
iRet = MSRONLIMIT;
}
if ((msr & MSR__AC_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Air-Cushion Error/");
iRet = MSRDEADCUSHION;
}
if ((msr & MSR__REF_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Ref. Pos'n Fail/");
}
if ((msr & MSR__POS_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Pos'n Fail/");
iRet = MSRPOSFAULT;
}
if ((msr & MSR__POS_FAULT) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Pos'n Fault/");
}
if ((msr & MSR__RUN_FAIL) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Run Fail/");
iRet = MSRRUNFAULT;
}
if ((msr & MSR__RUN_FAULT) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Run Fault/");
}
if ((msr & MSR__HALT) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Halt/");
iRet = MSRHALT;
}
if ((msr & MSR__HI_LIM) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Hit HiLim/");
iRet = MSRONLIMIT;
}
if ((msr & MSR__LO_LIM) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Hit LoLim/");
iRet = MSRONLIMIT;
}
if ((msr & MSR__STOPPED) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Stopped/");
iRet = MSRSTOP;
}
if ((msr & MSR__REF_OK) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Ref. Pos'n OK/");
}
if ((msr & MSR__OK) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "OK/");
}
if ((msr & MSR__BUSY) != 0) {
StrJoin(my_text, sizeof(my_text), text, "");
StrJoin(text, text_len, my_text, "Busy/");
}
len = strlen(text);
text[len - 1] = '\0';
}
return iRet;
}
/*-------------------------------------------------------------------------*/
static int EL734AnalyzeMSR(int msr, int ored_msr)
{
int iRet = 0;
/* this means the motor is done */
if (msr == 0) {
ored_msr = ored_msr & ~(MSR__BUSY); /* Zero "Busy" bit */
if (ored_msr == MSR__OK) {
iRet = MSROK;
} else {
if ((ored_msr & MSR__OK) != 0) {
iRet = MSROK;
} else {
iRet = MSROK;
}
if ((ored_msr & MSR__REF_OK) != 0) {
iRet = MSROK;
}
if ((ored_msr & MSR__LIM_ERR) != 0) {
return MSRONLIMIT;
}
if ((ored_msr & MSR__AC_FAIL) != 0) {
return MSRDEADCUSHION;
}
if ((ored_msr & MSR__REF_FAIL) != 0) {
iRet = MSRREF;
}
if ((ored_msr & MSR__POS_FAIL) != 0) {
return MSRPOSFAULT;
}
if ((ored_msr & MSR__POS_FAULT) != 0) {
iRet = MSRFAULT;
}
if ((ored_msr & MSR__RUN_FAIL) != 0) {
return MSRRUNFAULT;
}
if ((ored_msr & MSR__RUN_FAULT) != 0) {
iRet = MSRFAULT;
}
if ((ored_msr & MSR__HALT) != 0) {
return MSRHALT;
}
if ((ored_msr & MSR__HI_LIM) != 0) {
return MSRONLIMIT;
}
if ((ored_msr & MSR__LO_LIM) != 0) {
return MSRONLIMIT;
}
if ((ored_msr & MSR__STOPPED) != 0) {
return MSRSTOP;
}
}
/* the motor is still fighting along */
} else if ((msr & ~(0x2fff)) != 0) {
iRet = MSROK;
} else {
if ((msr & MSR__LIM_ERR) != 0) {
return MSRONLIMIT;
}
if ((msr & MSR__AC_FAIL) != 0) {
return MSRDEADCUSHION;
}
if ((msr & MSR__REF_FAIL) != 0) {
iRet = MSRREF;
}
if ((msr & MSR__POS_FAIL) != 0) {
return MSRPOSFAULT;
}
if ((msr & MSR__POS_FAULT) != 0) {
iRet = MSRFAULT;
}
if ((msr & MSR__RUN_FAIL) != 0) {
return MSRRUNFAULT;
}
if ((msr & MSR__RUN_FAULT) != 0) {
iRet = MSRFAULT;
}
if ((msr & MSR__HALT) != 0) {
return MSRHALT;
}
if ((msr & MSR__HI_LIM) != 0) {
return MSRONLIMIT;
}
if ((msr & MSR__LO_LIM) != 0) {
return MSRONLIMIT;
}
if ((msr & MSR__STOPPED) != 0) {
return MSRSTOP;
}
if ((msr & MSR__REF_OK) != 0) {
iRet = MSROK;
}
if ((msr & MSR__OK) != 0) {
iRet = MSROK;
}
if ((msr & MSR__BUSY) != 0) {
iRet = MSRBUSY;
}
}
return iRet;
}

1385
julcho.c

File diff suppressed because it is too large Load Diff

View File

@ -12,19 +12,20 @@
OBJ=psi.o buffer.o ruli.o sps.o pimotor.o charbychar.o\ OBJ=psi.o buffer.o ruli.o sps.o pimotor.o charbychar.o\
pipiezo.o sanswave.o faverage.o spss7.o\ pipiezo.o sanswave.o faverage.o spss7.o\
amorstat.o tasinit.o ptasdrive.o tasutil.o tasscan.o swmotor.o \ amorstat.o tasinit.o ptasdrive.o tasutil.o tasscan.o swmotor.o \
polterwrite.o ecb.o frame.o el734driv.o el734dc.o ecbdriv.o \ polterwrite.o ecb.o frame.o \
ecbcounter.o el737driv.o sinqhmdriv.o tdchm.o velodorn.o \ el737driv.o sinqhmdriv.o tdchm.o \
velodornier.o sanscook.o tecsdriv.o itc4driv.o itc4.o\ sanscook.o tecsdriv.o itc4driv.o itc4.o\
bruker.o ltc11.o A1931.o eurodriv.o slsmagnet.o \ bruker.o ltc11.o eurodriv.o \
el755driv.o serial.o scontroller.o t_update.o \ el755driv.o serial.o scontroller.o t_update.o \
t_rlp.o t_conv.o el737hpdriv.o dornier2.o el734hp.o \ t_rlp.o t_conv.o el737hpdriv.o el734hp.o \
el737hpv2driv.o swmotor2.o tricssupport.o amorcomp.o \ el737hpv2driv.o swmotor2.o tricssupport.o amorcomp.o \
$(MZOBJ) amordrive.o amorset.o sinqhttp.o slsecho.o\ $(MZOBJ) amordrive.o amorset.o sinqhttp.o slsecho.o\
dgrambroadcast.o sinq.o tabledrive.o julcho.o sinqhttpopt.o\ dgrambroadcast.o sinq.o tabledrive.o sinqhttpopt.o\
ritastorage.o poldizug.o audinelib.o delcam.o el737hpdrivsps.o \ ritastorage.o poldizug.o el737hpdrivsps.o \
rebin.o sanslirebin.o lmd200.o slsvme.o julprot.o sinqhttpprot.o \ rebin.o sanslirebin.o lmd200.o slsvme.o julprot.o sinqhttpprot.o \
pmacprot.o pfeifferprot.o termprot.o phytron.o autowin.o eigera2.o \ pmacprot.o pfeifferprot.o termprot.o phytron.o autowin.o eigera2.o \
tclClock.o tclDate.o tclUnixTime.o jvlprot.o tclClock.o tclDate.o tclUnixTime.o jvlprot.o epicscounter.o \
eigermono.o
.SECONDARY.: sanslirebin.c .SECONDARY.: sanslirebin.c

View File

@ -13,7 +13,7 @@ include ../sllinux_def
CC = gcc CC = gcc
CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 $(NI) -I$(TCLINC) -Ihardsup \ CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 $(NI) -I$(TCLINC) -Ihardsup \
-I.. -I. -MMD -DCYGNUS -DNONINTF -g $(DFORTIFY) \ -I.. -I. -MMD -DCYGNUS -DNONINTF $(DBG) $(DFORTIFY) \
-Wall -Wno-unused -Wunused-value -Wno-comment -Wno-switch -Werror -Wall -Wno-unused -Wunused-value -Wno-comment -Wno-switch -Werror
EXTRA=nintf.o EXTRA=nintf.o

92
psi.c
View File

@ -24,15 +24,12 @@
#include "site.h" #include "site.h"
#include <motor.h> #include <motor.h>
#include <site.h> #include <site.h>
#include "ecbdriv.h"
#include "ecbcounter.h"
#include "sinqhmdriv.i" #include "sinqhmdriv.i"
#include "tdchm.h" #include "tdchm.h"
#include "tecsdriv.h" #include "tecsdriv.h"
#include "itc4.h" #include "itc4.h"
#include "bruker.h" #include "bruker.h"
#include "ltc11.h" #include "ltc11.h"
#include "A1931.h"
#include "eurodriv.h" #include "eurodriv.h"
#include "el755driv.h" #include "el755driv.h"
#include <evdriver.i> #include <evdriver.i>
@ -110,10 +107,8 @@ static void AddPsiCommands(SicsInterp * pInter)
SCMD("MakeAmorStatus", AmorStatusFactory); SCMD("MakeAmorStatus", AmorStatusFactory);
SCMD("MakeECB", MakeECB); SCMD("MakeECB", MakeECB);
SCMD("MakeFocusAverager", MakeFA); SCMD("MakeFocusAverager", MakeFA);
SCMD("MakeJulCho", JulChoFactory);
SCMD("MakeLMD200", MakeLMD200); SCMD("MakeLMD200", MakeLMD200);
SCMD("MakePIMotor", PIMotorFactory); SCMD("MakePIMotor", PIMotorFactory);
SCMD("MakePoldiReiss", MakePoldiReiss);
SCMD("MakePSDFrame", MakeFrameFunc); SCMD("MakePSDFrame", MakeFrameFunc);
SCMD("MakeRitaFix", MakeRitaFix); SCMD("MakeRitaFix", MakeRitaFix);
SCMD("MakeRitaWin", MakeRitaWin); SCMD("MakeRitaWin", MakeRitaWin);
@ -132,6 +127,7 @@ static void AddPsiCommands(SicsInterp * pInter)
SCMD("PolterInstall", PolterInstall); SCMD("PolterInstall", PolterInstall);
SCMD("SerialInit", SerialInit); SCMD("SerialInit", SerialInit);
SCMD("MakeEiger", InitEiger); SCMD("MakeEiger", InitEiger);
SCMD("MakeEigerMono", InitEigerMono);
PCMD("cnvrt", CnvrtAction); PCMD("cnvrt", CnvrtAction);
/* /*
@ -146,8 +142,6 @@ static void AddPsiCommands(SicsInterp * pInter)
} }
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
MotorDriver *CreateEL734(SConnection * pCon, int argc, char *argv[]);
MotorDriver *CreateEL734DC(SConnection * pCon, int argc, char *argv[]);
MotorDriver *CreateEL734HP(SConnection * pCon, int argc, char *argv[]); MotorDriver *CreateEL734HP(SConnection * pCon, int argc, char *argv[]);
MotorDriver *CreateEL734HPT(SConnection * pCon, int argc, char *argv[]); MotorDriver *CreateEL734HPT(SConnection * pCon, int argc, char *argv[]);
MotorDriver *MakePiPiezo(Tcl_Interp * pTcl, char *pArray); MotorDriver *MakePiPiezo(Tcl_Interp * pTcl, char *pArray);
@ -173,18 +167,6 @@ static pMotor CreatePsiMotor(SConnection * pCon, int argc, char *argv[])
SCWrite(pCon, pBueffel, eError); SCWrite(pCon, pBueffel, eError);
return NULL; return NULL;
} }
} else if (strcmp(argv[1], "el734") == 0) {
pDriver = (MotorDriver *) CreateEL734(pCon, argc - 2, &argv[2]);
if (!pDriver) {
return NULL;
}
/* create the motor */
pNew = MotorInit("EL734", argv[0], pDriver);
if (!pNew) {
snprintf(pBueffel,131, "Failure to create motor %s", argv[1]);
SCWrite(pCon, pBueffel, eError);
return NULL;
}
} else if (strcmp(argv[1], "el734hp") == 0) { } else if (strcmp(argv[1], "el734hp") == 0) {
pDriver = (MotorDriver *) CreateEL734HP(pCon, argc - 2, &argv[2]); pDriver = (MotorDriver *) CreateEL734HP(pCon, argc - 2, &argv[2]);
if (!pDriver) { if (!pDriver) {
@ -209,30 +191,6 @@ static pMotor CreatePsiMotor(SConnection * pCon, int argc, char *argv[])
SCWrite(pCon, pBueffel, eError); SCWrite(pCon, pBueffel, eError);
return NULL; return NULL;
} }
} else if (strcmp(argv[1], "el734dc") == 0) {
pDriver = (MotorDriver *) CreateEL734DC(pCon, argc - 2, &argv[2]);
if (!pDriver) {
return NULL;
}
/* create the motor */
pNew = MotorInit("EL734DC", argv[0], pDriver);
if (!pNew) {
snprintf(pBueffel,131, "Failure to create motor %s", argv[1]);
SCWrite(pCon, pBueffel, eError);
return NULL;
}
} else if (strcmp(argv[1], "ecb") == 0) {
pDriver = (MotorDriver *) CreateECBMotor(pCon, argc - 2, &argv[2]);
if (!pDriver) {
return NULL;
}
/* create the motor */
pNew = MotorInit("ECB", argv[0], pDriver);
if (!pNew) {
snprintf(pBueffel,131, "Failure to create motor %s", argv[0]);
SCWrite(pCon, pBueffel, eError);
return NULL;
}
} }
return pNew; return pNew;
} }
@ -246,6 +204,8 @@ extern pCounterDriver MakeEL737HPV2(SConnection * pCon, char *name,
int argc, char *argv[]); int argc, char *argv[]);
pCounterDriver MakeEL737hpsps(SConnection * pCon, char *name, pCounterDriver MakeEL737hpsps(SConnection * pCon, char *name,
int argc, char *argv[]); int argc, char *argv[]);
pCounterDriver MakeEPICSCounter(char *rootname);
/*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/
static pCounterDriver CreatePsiCounterDriver(SConnection * pCon, static pCounterDriver CreatePsiCounterDriver(SConnection * pCon,
int argc, char *argv[]) int argc, char *argv[])
@ -263,20 +223,17 @@ static pCounterDriver CreatePsiCounterDriver(SConnection * pCon,
pNew = MakeEL737hpsps(pCon, argv[1], argc - 3, &argv[3]); pNew = MakeEL737hpsps(pCon, argv[1], argc - 3, &argv[3]);
} else if (strcmp(argv[2], "el737hpv2") == 0) { } else if (strcmp(argv[2], "el737hpv2") == 0) {
pNew = MakeEL737HPV2(pCon, argv[1], argc - 3, &argv[3]); pNew = MakeEL737HPV2(pCon, argv[1], argc - 3, &argv[3]);
} else if (strcmp(argv[2], "ecb") == 0) { } else if (strcmp(argv[2], "epics") == 0) {
if (argc < 4) { if (argc < 4) {
SCWrite(pCon, SCWrite(pCon,
"ERROR: insufficient no of arguments to create ECB counter", "ERROR: insufficient no of arguments to create epics counter",
eError); eError);
return NULL; return NULL;
} }
pNew = MakeECBCounter(argv[3]); pNew = MakeEPICSCounter(argv[3]);
} }
return pNew; return pNew;
} }
/*-------------------------------------------------------------------*/
extern pHistDriver MakeDelcamHM(pStringDict options); /* in delcam.c */
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
static HistDriver *CreatePsiHistMem(char *name, pStringDict pOptions) static HistDriver *CreatePsiHistMem(char *name, pStringDict pOptions)
{ {
@ -288,24 +245,6 @@ static HistDriver *CreatePsiHistMem(char *name, pStringDict pOptions)
pNew = MakeTDCHM(pOptions); pNew = MakeTDCHM(pOptions);
} else if (strcmp(name, "sinqhttp") == 0) { } else if (strcmp(name, "sinqhttp") == 0) {
pNew = CreateSinqHttpDriver(pOptions); pNew = CreateSinqHttpDriver(pOptions);
} else if (strcmp(name, "delcam") == 0) {
pNew = MakeDelcamHM(pOptions);
}
return pNew;
}
/*-------------------------------------------------------------------*/
extern pVelSelDriv VSCreateDornierSINQ(char *name, Tcl_Interp * pTcl);
extern pVelSelDriv VSCreateDornier2003(char *name, Tcl_Interp * pTcl);
/*-------------------------------------------------------------------*/
static pVelSelDriv CreatePsiVelSelDriv(char *name, char *array,
Tcl_Interp * pTcl)
{
pVelSelDriv pNew = NULL;
if (strcmp(name, "dornier") == 0) {
pNew = VSCreateDornierSINQ(array, pTcl);
} else if (strcmp(name, "dornier2003") == 0) {
pNew = VSCreateDornier2003(array, pTcl);
} }
return pNew; return pNew;
} }
@ -375,7 +314,6 @@ static void ConfigureController(char *name, pEVControl pNew,
} }
/*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/
extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
extern pEVDriver CreateSLSVMEDriv(int argc, char *argv[]); extern pEVDriver CreateSLSVMEDriv(int argc, char *argv[]);
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
@ -436,28 +374,12 @@ static pEVControl InstallPsiEnvironmentController(SicsInterp * pSics,
commandInstalled = 1; commandInstalled = 1;
} }
} }
} else if (strcmp(argv[3], "a1931") == 0) {
checkError = 1;
pDriv = CreateA1931Driver(argc - 4, &argv[4]);
if (pDriv != NULL) {
pNew = CreateEVController(pDriv, argv[2], &status);
if (pNew != NULL) {
AddCommand(pSics, argv[2], A1931Action, DeleteEVController, pNew);
commandInstalled = 1;
}
}
} else if (strcmp(argv[3], "euro") == 0) { } else if (strcmp(argv[3], "euro") == 0) {
checkError = 1; checkError = 1;
pDriv = CreateEURODriv(argc - 4, &argv[4]); pDriv = CreateEURODriv(argc - 4, &argv[4]);
if (pDriv != NULL) { if (pDriv != NULL) {
pNew = CreateEVController(pDriv, argv[2], &status); pNew = CreateEVController(pDriv, argv[2], &status);
} }
} else if (strcmp(argv[3], "psi-dsp") == 0) {
checkError = 1;
pDriv = CreateSLSDriv(argc - 4, &argv[4]);
if (pDriv != NULL) {
pNew = CreateEVController(pDriv, argv[2], &status);
}
} else if (strcmp(argv[3], "vme-dsp") == 0) { } else if (strcmp(argv[3], "vme-dsp") == 0) {
checkError = 1; checkError = 1;
pDriv = CreateSLSVMEDriv(argc - 4, &argv[4]); pDriv = CreateSLSVMEDriv(argc - 4, &argv[4]);
@ -538,7 +460,7 @@ pSite getSite(void)
sitePSI->CreateMotor = CreatePsiMotor; sitePSI->CreateMotor = CreatePsiMotor;
sitePSI->CreateCounterDriver = CreatePsiCounterDriver; sitePSI->CreateCounterDriver = CreatePsiCounterDriver;
sitePSI->CreateHistogramMemoryDriver = CreatePsiHistMem; sitePSI->CreateHistogramMemoryDriver = CreatePsiHistMem;
sitePSI->CreateVelocitySelector = CreatePsiVelSelDriv; sitePSI->CreateVelocitySelector = NULL;
sitePSI->CreateControllerDriver = CreatePsiController; sitePSI->CreateControllerDriver = CreatePsiController;
sitePSI->InstallEnvironmentController = sitePSI->InstallEnvironmentController =
InstallPsiEnvironmentController; InstallPsiEnvironmentController;

View File

@ -20,6 +20,7 @@
#include <ghttp.h> #include <ghttp.h>
#include <stptok.h> #include <stptok.h>
#include <countdriv.h> #include <countdriv.h>
#include <trace.h>
extern char *trim(char *); extern char *trim(char *);
/*=================================================================== /*===================================================================
@ -133,6 +134,7 @@ static int sinqHttpGet(pSinqHttp self, char *request)
* try two times: a reconnect is no error * try two times: a reconnect is no error
*/ */
ghttp_prepare(self->syncRequest); ghttp_prepare(self->syncRequest);
traceIO(self->hmAddress,"OUT:%s",request);
httpStatus = ghttp_process(self->syncRequest); httpStatus = ghttp_process(self->syncRequest);
if (httpStatus != ghttp_done) { if (httpStatus != ghttp_done) {
ghttp_close(self->syncRequest); ghttp_close(self->syncRequest);
@ -145,6 +147,7 @@ static int sinqHttpGet(pSinqHttp self, char *request)
self->errorCode = SERVERERROR; self->errorCode = SERVERERROR;
return 0; return 0;
} else { } else {
traceIO(self->hmAddress,"IN:%s",request);
return sinqHttpCheckResponse(self); return sinqHttpCheckResponse(self);
} }
return 1; return 1;
@ -416,6 +419,7 @@ static int SinqHttpStatus(pHistDriver self, SConnection * pCon)
if (pPriv->asyncRunning == 0) { if (pPriv->asyncRunning == 0) {
status = sinqHttpGetPrepare(pPriv, statusdaq); status = sinqHttpGetPrepare(pPriv, statusdaq);
traceIO(pPriv->hmAddress,"OUT:%s", statusdaq);
ghttp_set_sync(pPriv->syncRequest, ghttp_async); ghttp_set_sync(pPriv->syncRequest, ghttp_async);
ghttp_prepare(pPriv->syncRequest); ghttp_prepare(pPriv->syncRequest);
if (status != 1) { if (status != 1) {
@ -446,6 +450,7 @@ static int SinqHttpStatus(pHistDriver self, SConnection * pCon)
if (status != 1) { if (status != 1) {
return HWFault; return HWFault;
} }
traceIO(pPriv->hmAddress,"IN:%s", statusdaq);
break; break;
} }
@ -569,6 +574,8 @@ static int SinqHttpGetHistogram(pHistDriver self, SConnection * pCon,
snprintf(command, 255, "%s?bank=%d&start=%d&end=%d", gethm, bank, snprintf(command, 255, "%s?bank=%d&start=%d&end=%d", gethm, bank,
start, end); start, end);
/* printf("SinqHttpGetHistogram:%d-%d\n", start,end); */
status = sinqHttpGet(pPriv, command); status = sinqHttpGet(pPriv, command);
if (status != 1) { if (status != 1) {
return HWFault; return HWFault;

File diff suppressed because it is too large Load Diff

View File

@ -1,385 +0,0 @@
/*-------------------------------------------------------------------------
V E L O D O R N
Utility functions for talking to a Dornier velocity selector in the
SINQ setup.
Mark Koennecke, Juli 1997
Updated to decode the new dornier status messages as coughed up by the new
style Dornier software.
Mark Koennecke, July 2003
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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include <sics.h>
#include <fortify.h>
#include "hardsup/sinq_prototypes.h"
#include "velodorn.h"
#include "hardsup/serialsinq.h"
#include <serialwait.h>
#define TOK_BUF_L 25
/*--------------------------- analyse Dornier status string ----------------*/
int AnalyseDornierStatus(char *pText, pDornierStatus pResult)
{
int cnt, key_id, sl, sts;
long err;
char ena_str[] = "ENABLED";
char dis_str[] = "DISABLED";
char keys[16][9] = {
"Status:\0 ",
"S_DREH:\0 ",
"I_DREH:\0 ",
"P_VERL:\0 ",
"STROM:\0 ",
"T_ROT:\0 ",
"T_GEH:\0 ",
"T_VOR:\0 ",
"T_RUECK:\0",
"DURCHFL:\0",
"VAKUUM:\0 ",
"BESCHL:\0 ",
"KOM: \0 ",
"DATE: \0 ",
"TIME: \0 ",
"Hz:\0 "
};
char tok_buf[TOK_BUF_L], *ptr_token, *ptr_src, *ptr;
const char tok_c[] = "/\\\0";
char status[255];
ptr_src = pText;
memset(pResult, 0, sizeof(DornierStatus));
/* skip over first token, should be command echo */
ptr_token = strtok(ptr_src, tok_c);
if (ptr_token == NULL)
return 0; /* error */
strcpy(pResult->echo, (const char *) ptr_token);
ptr_src += strlen(ptr_token);
ptr_src = NULL; /* necessary for further search with strtok */
for (;;) {
/* read text till next separator '/' */
ptr_token = strtok(ptr_src, tok_c);
if (ptr_token == NULL)
break;
strcpy(tok_buf, ptr_token);
for (key_id = 0; key_id <= 15; key_id++) {
/* search key ? */
sl = strlen(keys[key_id]);
if (strncmp(&keys[key_id][0], tok_buf, sl) == 0) {
/* step over key */
for (cnt = 0; cnt + sl < TOK_BUF_L; cnt++)
tok_buf[cnt] = tok_buf[cnt + sl];
switch (key_id) {
case 0:{
strcpy(pResult->rm, tok_buf);
break;
}
case 1:{
sscanf(tok_buf, "%d", &pResult->nom_rpm);
break;
}
case 2:{
sscanf(tok_buf, "%d", &pResult->cur_rpm);
break;
}
case 3:{
sscanf(tok_buf, "%d", &pResult->pwr);
break;
}
case 4:{
sscanf(tok_buf, "%f", &pResult->curr);
break;
}
case 5:{
sscanf(tok_buf, "%d", &pResult->rot_temp);
break;
}
case 6:{
sscanf(tok_buf, "%d", &pResult->cont_temp);
break;
}
case 7:{
sscanf(tok_buf, "%d", &pResult->inl_temp);
break;
}
case 8:{
sscanf(tok_buf, "%d", &pResult->outl_temp);
break;
}
case 9:{
sscanf(tok_buf, "%f", &pResult->cool_wat);
break;
}
case 10:{
sscanf(tok_buf, "%f", &pResult->vacuum);
break;
}
case 11:{
sscanf(tok_buf, "%f", &pResult->accel);
break;
}
case 12:{
if (strcmp(tok_buf, ena_str) == 0) {
pResult->komm = 1;
break;
}
if (strcmp(tok_buf, dis_str) == 0) {
pResult->komm = 0;
break;
}
break;
}
case 13:
break; /* date */
case 14:
break; /* time */
case 15:{
sscanf(tok_buf, "%d", &pResult->iHz);
break;
}
}
}
}
}
return (1);
}
/*--------------------------- analyse Dornier status string ----------------
This is the version for the NGS037 software from Dornier. Main difference
is that the keycodes are in germlish.
-------------------------------------------------------------------------*/
int DecodeNewDornierStatus(char *pText, pDornierStatus pResult)
{
int cnt, key_id, sl, sts;
long err;
char ena_str[] = "ENABLED";
char dis_str[] = "DISABLED";
char keys[16][14] = {
"MODE:\0 ",
"R_SPEED:\0 ",
"A_SPEED:\0 ",
"P_LOSS:\0 ",
"R_Current:\0 ",
"T_ROT:\0 ",
"T_HHH:\0 ",
"T_INL:\0 ",
"T_OUT:\0",
"F_RATE:\0",
"A_Vac:\0 ",
"V_OSC:\0 ",
"COM: \0 ",
"DATE: \0 ",
"TIME: \0 ",
"Hz:\0 "
};
char tok_buf[TOK_BUF_L], *ptr_token, *ptr_src, *ptr;
const char tok_c[] = "/\\\0";
char status[255];
ptr_src = pText;
memset(pResult, 0, sizeof(DornierStatus));
/* skip over first token, should be command echo */
ptr_token = strtok(ptr_src, tok_c);
if (ptr_token == NULL)
return 0; /* error */
strcpy(pResult->echo, (const char *) ptr_token);
ptr_src += strlen(ptr_token);
ptr_src = NULL; /* necessary for further search with strtok */
for (;;) {
/* read text till next separator '/' */
ptr_token = strtok(ptr_src, tok_c);
if (ptr_token == NULL)
break;
strcpy(tok_buf, ptr_token);
for (key_id = 0; key_id <= 15; key_id++) {
/* search key ? */
sl = strlen(keys[key_id]);
if (strncmp(&keys[key_id][0], tok_buf, sl) == 0) {
/* step over key */
for (cnt = 0; cnt + sl < TOK_BUF_L; cnt++)
tok_buf[cnt] = tok_buf[cnt + sl];
switch (key_id) {
case 0:{
strcpy(pResult->rm, tok_buf);
break;
}
case 1:{
sscanf(tok_buf, "%d", &pResult->nom_rpm);
break;
}
case 2:{
sscanf(tok_buf, "%d", &pResult->cur_rpm);
break;
}
case 3:{
sscanf(tok_buf, "%d", &pResult->pwr);
break;
}
case 4:{
sscanf(tok_buf, "%f", &pResult->curr);
break;
}
case 5:{
sscanf(tok_buf, "%d", &pResult->rot_temp);
break;
}
case 6:{
sscanf(tok_buf, "%d", &pResult->cont_temp);
break;
}
case 7:{
sscanf(tok_buf, "%d", &pResult->inl_temp);
break;
}
case 8:{
sscanf(tok_buf, "%d", &pResult->outl_temp);
break;
}
case 9:{
sscanf(tok_buf, "%f", &pResult->cool_wat);
break;
}
case 10:{
sscanf(tok_buf, "%f", &pResult->vacuum);
break;
}
case 11:{
sscanf(tok_buf, "%f", &pResult->accel);
break;
}
case 12:{
if (strcmp(tok_buf, ena_str) == 0) {
pResult->komm = 1;
break;
}
if (strcmp(tok_buf, dis_str) == 0) {
pResult->komm = 0;
break;
}
break;
}
case 13:
break; /* date */
case 14:
break; /* time */
case 15:{
sscanf(tok_buf, "%d", &pResult->iHz);
break;
}
}
}
}
}
return (1);
}
/*-------------------------------------------------------------------------*/
int DornierSend(void **pData, char *pCommand, char *pReply, int iRepLen)
{
char pOldCom[10];
char *pPtr;
int iRet;
/* first copy the command send out, in order to test for echo */
pPtr = pCommand;
memset(pOldCom, 0, 10);
while (isspace(*pPtr) && (*pPtr != '\0')) {
pPtr++;
}
if (*pPtr == '\0') { /* no command */
return NOCOMMAND;
}
strncpy(pOldCom, pPtr, 3); /* strlcpy probably wrong here */
iRet = SerialWriteRead(pData, pCommand, pReply, iRepLen);
/*
iRet = SerialSicsExecute(pData,pCommand,pReply,iRepLen);
*/
if (iRet != 1) {
return iRet; /* an error ocurred */
}
/* try to find command in the reply */
pPtr = strstr(pReply, pOldCom);
if (pPtr == NULL) {
SICSLogWrite("Velocity Selector: Bad Reply:", eError);
SICSLogWrite(pReply, eError);
return ECHOMISSING;
}
return 1;
}
/*-------------------------------------------------------------------------*/
int GetDornierStatus(void **pData, pDornierStatus pDornier)
{
char pCommand[10] = { "???" };
char pReply[256];
int iRet;
/* send command */
iRet = DornierSend(pData, pCommand, pReply, 255);
if (iRet < 0) {
return iRet;
}
if (strlen(pReply) < 100) {
SICSLogWrite("Velocity Selector: Bad Reply:", eError);
SICSLogWrite(pReply, eError);
return INVALIDSTATUS;
}
/* analyse reply */
iRet = AnalyseDornierStatus(pReply, pDornier);
if (!iRet) {
return BADANALYSIS;
}
if (pDornier->cur_rpm > 70000) {
printf("Shitty status reply: %s detected \n", pReply);
}
return 1;
}

View File

@ -1,58 +0,0 @@
#line 47 "velodorn.w"
/*---------------------------------------------------------------------------
V E L O D O R N
a set of utility functions needed in order to communicate with a
Dornier velocity selector through the SINQ system.
Mark Koennecke, Juli 1997
updated to support new format fo status messages, Mark Koennecke, July 2003
copyright: see implementation file.
------------------------------------------------------------------------------*/
#ifndef VELODORN
#define VELODORN
/*-------------------- a data structure for status analysis ---------------*/
typedef struct {
char echo[30]; /* echo of command */
char rm[10]; /* operation status: REG == adjusting, STB == idle,
BRE == braking */
int nom_rpm; /* envisaged rotation */
int cur_rpm; /* actual rotation speed */
int pwr; /* loss current, only valid after check */
float curr; /* electircal current */
int rot_temp; /* temperature of rotor */
int cont_temp; /* temperature of housing */
int inl_temp; /* in temperature of cooling water */
int outl_temp; /* temperature of cooling water after
velocity selector */
float cool_wat; /* cooling water flow (l/minute) */
float vacuum; /* vacuum (mbar) */
float accel; /* rotation acceleration (g) */
int komm; /* communication status PC-Host,
0 = enabled, 1 = disabled
*/
int iHz;
} DornierStatus, *pDornierStatus;
/*--------- error codes */
#define NOCOMMAND -300
#define ECHOMISSING -302
#define BADANALYSIS -303
#define STARTTIMEOUT -304
#define INVALIDSTATUS -305
/*------ functions */
#line 41 "velodorn.w"
int GetDornierStatus(void **pData, pDornierStatus pDornier);
int DornierSend(void **pData, char *pCommand, char *pReply, int iLen);
int DecodeNewDornierStatus(char *pText, pDornierStatus pDornier);
#line 92 "velodorn.w"
#endif

View File

@ -1,636 +0,0 @@
/*--------------------------------------------------------------------------
V E L O D O R N I E R
A driver for a Dornier velocity selector, connected to our world
via a terminal server and TCP/IP. Please note, that the protocoll
implemented by the velocity selector PC has been changed in the following
ways from the standard as supplied by Dornier:
- no messages we have not asked for.
- The whole response will be concatenated in a string, each item
separated by a /. At the end is a single <CR><LF>. This is because
our terminal server reads only up to the first terminator.
Author: Mark Koennecke, Juli 1997
Thoroughly revised: October 1997 Mark Koennecke
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 "sics.h"
#include <string.h>
#include <math.h>
#include <tcl.h>
#include <time.h>
#include <fortify.h>
typedef struct __VelSelDriv *pVelSelDriv;
#include <velodriv.h>
#include "velodorn.h"
#include "hardsup/serialsinq.h"
#include "hardsup/el734_def.h"
#include "hardsup/el734fix.h"
#include <serialwait.h>
/* VELO* MUST be the same as in velo.i!*/
#define VELOREDO -1
#define VELOFAIL 0
#define VELOOK 1
#define VSNOCON 0
#define VSOK 1
#define VSACCEL -7
#define VSFAIL -2
typedef enum { vStart, eRegel, eHalted } eVeloMode;
#define RPMALIFE 3090
/*----------------------------- The private data structure ---------------*/
typedef struct {
char *pComputer;
int iPort;
int iChannel;
int iTimeOut;
int iLastError;
void *pData;
eVeloMode eVelo;
time_t t_End;
float fTarget;
int iBusy;
float fLastRPM;
} Dornier, *pDornier;
/*----------------------------------------------------------------------------*/
static int GetDornierPos(pVelSelDriv self, float *fPos)
{
pDornier pDorn = NULL;
DornierStatus DStatus;
int iRet;
assert(self);
pDorn = (pDornier) self->pPrivate;
if (pDorn->iBusy) {
*fPos = pDorn->fLastRPM;
return 1;
}
pDorn->iBusy = 1;
iRet = GetDornierStatus(&pDorn->pData, &DStatus);
pDorn->iBusy = 0;
if (iRet < 0) {
*fPos = -9999.;
return 0;
}
*fPos = DStatus.cur_rpm;
pDorn->fLastRPM = DStatus.cur_rpm;
return 1;
}
/*--------------------------------------------------------------------------*/
static int DornierHalt(pVelSelDriv self)
{
pDornier pDorn = NULL;
int iRet;
char pCom[] = { "HAL" };
char pAnswer[80];
assert(self);
pDorn = (pDornier) self->pPrivate;
iRet = SerialWriteRead(&pDorn->pData, pCom, pAnswer, 79);
/* iRet = SerialSicsExecute(&pDorn->pData, pCom,pAnswer,79);
*/
pDorn->eVelo = eHalted;
if (iRet != 1) {
pDorn->iLastError = iRet;
return 0;
}
return 1;
}
/*----------------------------------------------------------------------------*/
static int DornierRun(pVelSelDriv self, float fVal)
{
int iRet;
char pCommand[50], pAnswer[50];
pDornier pDorn = NULL;
assert(self);
pDorn = (pDornier) self->pPrivate;
/* less then zero, means halt in this case */
if (fVal < RPMALIFE) {
DornierHalt(self);
return 1;
}
/* if busy, wait until free */
while (pDorn->iBusy) {
SicsWait(1);
}
switch (pDorn->eVelo) {
case eHalted:
strcpy(pCommand, "SST");
pDorn->fTarget = fVal;
pDorn->eVelo = vStart;
pDorn->t_End = time(NULL) + 1800; /* start time + 30 min */
break;
case eRegel:
sprintf(pCommand, "SDR %5u", (int) fVal);
pDorn->fTarget = fVal;
break;
}
pDorn->iBusy = 1;
iRet = SerialWriteRead(&pDorn->pData, pCommand, pAnswer, 49);
/* iRet = SerialSicsExecute(&pDorn->pData,pCommand,pAnswer,49);
*/
pDorn->iBusy = 0;
if (iRet != 1) {
pDorn->iLastError = iRet;
return 0;
}
return 1;
}
/*--------------------------------------------------------------------------*/
static int DornierError(pVelSelDriv self, int *iCode, char *error,
int iErrLen)
{
pDornier pDorn = NULL;
assert(self);
pDorn = (pDornier) self->pPrivate;
*iCode = pDorn->iLastError;
switch (pDorn->iLastError) {
case NOCOMMAND:
strlcpy(error, "No command was specified, internal error", iErrLen);
break;
case ECHOMISSING:
strlcpy(error, "No echo received, may be busy", iErrLen);
break;
case BADANALYSIS:
strlcpy(error, "Error analysing status messge", iErrLen);
break;
case STARTTIMEOUT:
strlcpy(error, "Velocity Selector failed to start", iErrLen);
break;
default:
SerialError(pDorn->iLastError, error, iErrLen);
break;
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int DornierFixIt(pVelSelDriv self, int iError)
{
pDornier pDorn = NULL;
int iRet;
assert(self);
pDorn = (pDornier) self->pPrivate;
switch (iError) {
/* network errors */
case NOCONNECTION:
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:
SerialClose(&pDorn->pData);
iRet = SerialForceOpen(&pDorn->pData, pDorn->pComputer,
pDorn->iPort, pDorn->iChannel);
if (iRet != 1) {
return VELOREDO;
} else {
return VELOFAIL;
}
break;
/* handable protocoll errors */
case ECHOMISSING:
case EL734__BAD_TMO:
case -1:
case TIMEOUT:
return VELOREDO;
break;
case STARTTIMEOUT:
return VELOFAIL;
break;
case INVALIDSTATUS:
return VELOREDO;
break;
default:
return VELOFAIL;
break;
}
return VELOFAIL;
}
/*--------------------------------------------------------------------------*/
static int DornierStat(pVelSelDriv self, int *iCode, float *fCur)
{
pDornier pDorn = NULL;
int iRet, iErrStat;
DornierStatus sStatus;
char pCommand[80];
char pAnswer[80];
float fDelta;
static int iCount = 0;
assert(self);
pDorn = (pDornier) self->pPrivate;
/* if busy, return VSACCEL */
if (pDorn->iBusy) {
*fCur = pDorn->fLastRPM;
return VSACCEL;
}
*iCode = ROTMOVE;
/* get the status */
pDorn->iBusy = 1;
iRet = GetDornierStatus(&pDorn->pData, &sStatus);
pDorn->iBusy = 0;
if (iRet < 0) {
iErrStat = DornierFixIt(self, iRet);
*iCode = 9384; /* ignore this one */
if (iErrStat == VELOREDO) {
/* the velcocity selector will not respond when busy.
Therefore such cases are interpreted as busy!
*/
return VSACCEL;
} else {
/* this is what we got if there is network trouble */
return VELOFAIL;
}
}
/* some serious logic because of multi - modes */
switch (pDorn->eVelo) {
case vStart:
*iCode = ROTSTART;
*fCur = 0.;
if (sStatus.cur_rpm >= RPMALIFE) {
sprintf(pCommand, "SDR %5u", (int) pDorn->fTarget);
pDorn->iBusy = 1;
iRet = SerialWriteRead(&pDorn->pData, pCommand, pAnswer, 49);
/* iRet = SerialSicsExecute(&pDorn->pData,pCommand,pAnswer,49);
*/
pDorn->iBusy = 0;
pDorn->eVelo = eRegel;
iCount = 0;
if (iRet != 1) {
pDorn->iLastError = iRet;
return VELOFAIL;
}
return VSACCEL;
} else {
if (time(NULL) > pDorn->t_End) {
pDorn->iLastError = STARTTIMEOUT;
return VELOFAIL;
}
return VSACCEL;
}
break;
case eRegel:
*iCode = ROTMOVE;
*fCur = (float) sStatus.cur_rpm;
pDorn->fLastRPM = *fCur;
fDelta = sStatus.cur_rpm - sStatus.nom_rpm;
if (fDelta < 0) {
fDelta = -fDelta;
}
if (fDelta > self->fTolerance) {
iCount = 0;
return VSACCEL;
} else {
iCount++;
if (iCount > 4) {
return VSOK;
} else {
return VSACCEL;
}
}
case eHalted:
if (sStatus.iHz > 5) {
*iCode = ROTMOVE;
*fCur = (float) sStatus.cur_rpm;
pDorn->fLastRPM = *fCur;
return VSACCEL;
} else {
return VSOK;
}
break;
}
return VELOOK;
}
/*-------------------------------------------------------------------------*/
static int DornierText(pVelSelDriv self, char *pText, int iTextLen)
{
pDornier pDorn = NULL;
int iRet, iErrStat;
DornierStatus sStatus;
char pBueffel[1024];
char pHelp[80];
assert(self);
pDorn = (pDornier) self->pPrivate;
/* get the status */
iRet = GetDornierStatus(&pDorn->pData, &sStatus);
if (iRet < 0) {
pDorn->iLastError = iRet;
return 0;
}
/* format it to a string */
sprintf(pHelp, "RPM: %d , should %d\n", sStatus.cur_rpm,
sStatus.nom_rpm);
strcpy(pBueffel, pHelp);
sprintf(pHelp, "State: %s\n", sStatus.rm);
strcat(pBueffel, pHelp);
sprintf(pHelp, "Current: %d\n", sStatus.pwr);
strcat(pBueffel, pHelp);
sprintf(pHelp, "Rotor T: %d, Housing T: %d\n", sStatus.rot_temp,
sStatus.cont_temp);
strcat(pBueffel, pHelp);
sprintf(pHelp, "Cooling: In-T: %d, Out-T: %d, Flow: %f\n",
sStatus.inl_temp, sStatus.outl_temp, sStatus.cool_wat);
strcat(pBueffel, pHelp);
sprintf(pHelp, "Vaccum: %f, Accel: %f", sStatus.vacuum, sStatus.accel);
strcat(pBueffel, pHelp);
strlcpy(pText, pBueffel, iTextLen);
return 1;
}
/*------------------------------------------------------------------------*/
static int SimSetRot(pVelSelDriv self, float fNew)
{
return 1;
}
/*------------------------------------------------------------------------*/
static int DornierLoss(pVelSelDriv self, float *fLoss)
{
pDornier pDorn = NULL;
int iRet, iErrStat, iDelta;
DornierStatus DStatus;
char pCommand[] = { "BRE" };
char pAnswer[80];
static int iCount;
static int iError;
assert(self);
pDorn = (pDornier) self->pPrivate;
/* wait until not busy, to do it */
while (pDorn->iBusy) {
SicsWait(1);
}
/* send a command */
pDorn->iBusy = 1;
iRet = SerialWriteRead(&pDorn->pData, pCommand, pAnswer, 79);
pDorn->iBusy = 0;
if (iRet != 1) {
pDorn->iLastError = iRet;
return 0;
}
/* wait 10 seconds before doing anything */
SicsWait(10);
/* loop until back to speed again */
for (;;) {
iRet = GetDornierStatus(&pDorn->pData, &DStatus);
if (iRet) {
iError = 0;
iDelta = DStatus.cur_rpm - DStatus.nom_rpm;
if (iDelta < 0) {
iDelta = -iDelta;
}
if (iDelta < 15) {
iCount++;
if (iCount > 4) {
break;
}
} else {
iCount = 0;
}
} else {
iError++;
if (iError > 10) {
break;
}
}
}
*fLoss = DStatus.pwr;
return 1;
}
/*-------------------------------------------------------------------------*/
static void DornierKill(void *pData)
{
pDornier pDorn = NULL;
pDorn = (pDornier) pData;
assert(pDorn);
SerialSend(&pDorn->pData, "TTY");
SerialClose(&pDorn->pData);
if (pDorn->pComputer) {
free(pDorn->pComputer);
}
free(pDorn);
}
/*------------------------------------------------------------------------*/
static int DornierInit(pVelSelDriv self, SConnection * pCon)
{
pDornier pDorn = NULL;
int iRet, iError;
char pError[80], pBueffel[256];
assert(self);
pDorn = (pDornier) self->pPrivate;
assert(pDorn);
/* if there is no connection, open it */
if (!pDorn->pData) {
iRet = SerialForceOpen(&pDorn->pData, pDorn->pComputer,
pDorn->iPort, pDorn->iChannel);
if (iRet != 1) {
SerialError(iRet, pError, 79);
sprintf(pBueffel, "ERROR: %s when initialising Velocity selector",
pError);
SCWrite(pCon, pBueffel, eError);
return 0;
}
SerialConfig(&pDorn->pData, pDorn->iTimeOut);
SerialATerm(&pDorn->pData, "1\r");
SerialSendTerm(&pDorn->pData, "\n");
}
/* tell him that we want control */
iRet = DornierSend(&pDorn->pData, "REM", pError, 79);
if (iRet != 1) {
sprintf(pBueffel,
"ERROR: %s while switching velocity selector to remote",
pError);
SCWrite(pCon, pBueffel, eError);
return 1;
}
pDorn->eVelo = eHalted;
pDorn->iBusy = 0;
return 1;
}
/*-------------------------------------------------------------------------*/
pVelSelDriv VSCreateDornierSINQ(char *name, Tcl_Interp * pTcl)
{
pVelSelDriv pNew = NULL;
pDornier pDorn = NULL;
char *pPtr = NULL;
int iVal, iRet;
/* the most likely error is the parameters specified are wrong!
So check this first. We''ll use Tcl's result for error reporting.
name is the name of an Tcl array which should hold the info
necessary
*/
/* allocate a Dornier structure */
pDorn = (pDornier) malloc(sizeof(Dornier));
if (!pDorn) {
return NULL;
}
memset(pDorn, 0, sizeof(Dornier));
/* host name */
pPtr = (char *) Tcl_GetVar2(pTcl, name, "Host", TCL_GLOBAL_ONLY);
if (!pPtr) {
Tcl_AppendResult(pTcl, "ERROR: no hostname found in", name, NULL);
free(pDorn);
return NULL;
}
pDorn->pComputer = strdup(pPtr);
/* port number */
pPtr = (char *) Tcl_GetVar2(pTcl, name, "Port", TCL_GLOBAL_ONLY);
if (!pPtr) {
Tcl_AppendResult(pTcl, "ERROR: no port number found in", name, NULL);
free(pDorn);
return NULL;
}
iRet = Tcl_GetInt(pTcl, pPtr, &iVal);
if (iRet != TCL_OK) {
free(pDorn->pComputer);
free(pDorn);
return NULL;
}
pDorn->iPort = iVal;
/* channel number */
pPtr = (char *) Tcl_GetVar2(pTcl, name, "Channel", TCL_GLOBAL_ONLY);
if (!pPtr) {
Tcl_AppendResult(pTcl, "ERROR: no channel number found in", name,
NULL);
free(pDorn);
return NULL;
}
iRet = Tcl_GetInt(pTcl, pPtr, &iVal);
if (iRet != TCL_OK) {
free(pDorn->pComputer);
free(pDorn);
return NULL;
}
pDorn->iChannel = iVal;
/* time out. This one gets defaulted when not specified */
pPtr = (char *) Tcl_GetVar2(pTcl, name, "Timeout", TCL_GLOBAL_ONLY);
if (!pPtr) {
pDorn->iTimeOut = 1000;
} else {
iRet = Tcl_GetInt(pTcl, pPtr, &iVal);
if (iRet != TCL_OK) {
pDorn->iTimeOut = 1000;
}
pDorn->iTimeOut = iVal;
}
/* business as usual: allocate memory */
pNew = (pVelSelDriv) malloc(sizeof(VelSelDriv));
if (!pNew) {
return NULL;
}
/* zero the world */
memset(pNew, 0, sizeof(VelSelDriv));
pNew->pPrivate = pDorn;
/* initialise function pointers */
pNew->DeletePrivate = DornierKill;
pNew->Halt = DornierHalt;
pNew->GetError = DornierError;
pNew->TryAndFixIt = DornierFixIt;
pNew->GetRotation = GetDornierPos;
pNew->SetRotation = DornierRun;
pNew->GetStatus = DornierStat;
pNew->GetDriverText = DornierText;
pNew->GetLossCurrent = DornierLoss;
pNew->Init = DornierInit;
/* done it */
return pNew;
}