- 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:
367
A1931.c
367
A1931.c
@ -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
20
A1931.h
@ -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
|
626
audinelib.c
626
audinelib.c
@ -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;
|
||||
}
|
79
audinelib.h
79
audinelib.h
@ -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
698
docho.c
@ -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;
|
||||
}
|
708
dornier2.c
708
dornier2.c
@ -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;
|
||||
}
|
640
ecbcounter.c
640
ecbcounter.c
@ -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;
|
||||
}
|
17
ecbcounter.h
17
ecbcounter.h
@ -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
|
43
ecbdriv.h
43
ecbdriv.h
@ -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
730
eigermono.c
Normal 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
892
el734dc.c
@ -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;
|
||||
}
|
905
el734driv.c
905
el734driv.c
@ -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;
|
||||
}
|
17
make_gen
17
make_gen
@ -12,19 +12,20 @@
|
||||
OBJ=psi.o buffer.o ruli.o sps.o pimotor.o charbychar.o\
|
||||
pipiezo.o sanswave.o faverage.o spss7.o\
|
||||
amorstat.o tasinit.o ptasdrive.o tasutil.o tasscan.o swmotor.o \
|
||||
polterwrite.o ecb.o frame.o el734driv.o el734dc.o ecbdriv.o \
|
||||
ecbcounter.o el737driv.o sinqhmdriv.o tdchm.o velodorn.o \
|
||||
velodornier.o sanscook.o tecsdriv.o itc4driv.o itc4.o\
|
||||
bruker.o ltc11.o A1931.o eurodriv.o slsmagnet.o \
|
||||
polterwrite.o ecb.o frame.o \
|
||||
el737driv.o sinqhmdriv.o tdchm.o \
|
||||
sanscook.o tecsdriv.o itc4driv.o itc4.o\
|
||||
bruker.o ltc11.o eurodriv.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 \
|
||||
$(MZOBJ) amordrive.o amorset.o sinqhttp.o slsecho.o\
|
||||
dgrambroadcast.o sinq.o tabledrive.o julcho.o sinqhttpopt.o\
|
||||
ritastorage.o poldizug.o audinelib.o delcam.o el737hpdrivsps.o \
|
||||
dgrambroadcast.o sinq.o tabledrive.o sinqhttpopt.o\
|
||||
ritastorage.o poldizug.o el737hpdrivsps.o \
|
||||
rebin.o sanslirebin.o lmd200.o slsvme.o julprot.o sinqhttpprot.o \
|
||||
pmacprot.o pfeifferprot.o termprot.o phytron.o autowin.o 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
|
||||
|
||||
|
@ -13,7 +13,7 @@ include ../sllinux_def
|
||||
|
||||
CC = gcc
|
||||
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
|
||||
|
||||
EXTRA=nintf.o
|
||||
|
92
psi.c
92
psi.c
@ -24,15 +24,12 @@
|
||||
#include "site.h"
|
||||
#include <motor.h>
|
||||
#include <site.h>
|
||||
#include "ecbdriv.h"
|
||||
#include "ecbcounter.h"
|
||||
#include "sinqhmdriv.i"
|
||||
#include "tdchm.h"
|
||||
#include "tecsdriv.h"
|
||||
#include "itc4.h"
|
||||
#include "bruker.h"
|
||||
#include "ltc11.h"
|
||||
#include "A1931.h"
|
||||
#include "eurodriv.h"
|
||||
#include "el755driv.h"
|
||||
#include <evdriver.i>
|
||||
@ -110,10 +107,8 @@ static void AddPsiCommands(SicsInterp * pInter)
|
||||
SCMD("MakeAmorStatus", AmorStatusFactory);
|
||||
SCMD("MakeECB", MakeECB);
|
||||
SCMD("MakeFocusAverager", MakeFA);
|
||||
SCMD("MakeJulCho", JulChoFactory);
|
||||
SCMD("MakeLMD200", MakeLMD200);
|
||||
SCMD("MakePIMotor", PIMotorFactory);
|
||||
SCMD("MakePoldiReiss", MakePoldiReiss);
|
||||
SCMD("MakePSDFrame", MakeFrameFunc);
|
||||
SCMD("MakeRitaFix", MakeRitaFix);
|
||||
SCMD("MakeRitaWin", MakeRitaWin);
|
||||
@ -132,6 +127,7 @@ static void AddPsiCommands(SicsInterp * pInter)
|
||||
SCMD("PolterInstall", PolterInstall);
|
||||
SCMD("SerialInit", SerialInit);
|
||||
SCMD("MakeEiger", InitEiger);
|
||||
SCMD("MakeEigerMono", InitEigerMono);
|
||||
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 *CreateEL734HPT(SConnection * pCon, int argc, char *argv[]);
|
||||
MotorDriver *MakePiPiezo(Tcl_Interp * pTcl, char *pArray);
|
||||
@ -173,18 +167,6 @@ static pMotor CreatePsiMotor(SConnection * pCon, int argc, char *argv[])
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
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) {
|
||||
pDriver = (MotorDriver *) CreateEL734HP(pCon, argc - 2, &argv[2]);
|
||||
if (!pDriver) {
|
||||
@ -209,30 +191,6 @@ static pMotor CreatePsiMotor(SConnection * pCon, int argc, char *argv[])
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
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;
|
||||
}
|
||||
@ -246,6 +204,8 @@ extern pCounterDriver MakeEL737HPV2(SConnection * pCon, char *name,
|
||||
int argc, char *argv[]);
|
||||
pCounterDriver MakeEL737hpsps(SConnection * pCon, char *name,
|
||||
int argc, char *argv[]);
|
||||
|
||||
pCounterDriver MakeEPICSCounter(char *rootname);
|
||||
/*-------------------------------------------------------------------*/
|
||||
static pCounterDriver CreatePsiCounterDriver(SConnection * pCon,
|
||||
int argc, char *argv[])
|
||||
@ -263,20 +223,17 @@ static pCounterDriver CreatePsiCounterDriver(SConnection * pCon,
|
||||
pNew = MakeEL737hpsps(pCon, argv[1], argc - 3, &argv[3]);
|
||||
} else if (strcmp(argv[2], "el737hpv2") == 0) {
|
||||
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) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: insufficient no of arguments to create ECB counter",
|
||||
"ERROR: insufficient no of arguments to create epics counter",
|
||||
eError);
|
||||
return NULL;
|
||||
}
|
||||
pNew = MakeECBCounter(argv[3]);
|
||||
pNew = MakeEPICSCounter(argv[3]);
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
extern pHistDriver MakeDelcamHM(pStringDict options); /* in delcam.c */
|
||||
/*--------------------------------------------------------------------*/
|
||||
static HistDriver *CreatePsiHistMem(char *name, pStringDict pOptions)
|
||||
{
|
||||
@ -288,24 +245,6 @@ static HistDriver *CreatePsiHistMem(char *name, pStringDict pOptions)
|
||||
pNew = MakeTDCHM(pOptions);
|
||||
} else if (strcmp(name, "sinqhttp") == 0) {
|
||||
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;
|
||||
}
|
||||
@ -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[]);
|
||||
/*------------------------------------------------------------------*/
|
||||
|
||||
@ -436,28 +374,12 @@ static pEVControl InstallPsiEnvironmentController(SicsInterp * pSics,
|
||||
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) {
|
||||
checkError = 1;
|
||||
pDriv = CreateEURODriv(argc - 4, &argv[4]);
|
||||
if (pDriv != NULL) {
|
||||
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) {
|
||||
checkError = 1;
|
||||
pDriv = CreateSLSVMEDriv(argc - 4, &argv[4]);
|
||||
@ -538,7 +460,7 @@ pSite getSite(void)
|
||||
sitePSI->CreateMotor = CreatePsiMotor;
|
||||
sitePSI->CreateCounterDriver = CreatePsiCounterDriver;
|
||||
sitePSI->CreateHistogramMemoryDriver = CreatePsiHistMem;
|
||||
sitePSI->CreateVelocitySelector = CreatePsiVelSelDriv;
|
||||
sitePSI->CreateVelocitySelector = NULL;
|
||||
sitePSI->CreateControllerDriver = CreatePsiController;
|
||||
sitePSI->InstallEnvironmentController =
|
||||
InstallPsiEnvironmentController;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <ghttp.h>
|
||||
#include <stptok.h>
|
||||
#include <countdriv.h>
|
||||
#include <trace.h>
|
||||
|
||||
extern char *trim(char *);
|
||||
/*===================================================================
|
||||
@ -133,6 +134,7 @@ static int sinqHttpGet(pSinqHttp self, char *request)
|
||||
* try two times: a reconnect is no error
|
||||
*/
|
||||
ghttp_prepare(self->syncRequest);
|
||||
traceIO(self->hmAddress,"OUT:%s",request);
|
||||
httpStatus = ghttp_process(self->syncRequest);
|
||||
if (httpStatus != ghttp_done) {
|
||||
ghttp_close(self->syncRequest);
|
||||
@ -145,6 +147,7 @@ static int sinqHttpGet(pSinqHttp self, char *request)
|
||||
self->errorCode = SERVERERROR;
|
||||
return 0;
|
||||
} else {
|
||||
traceIO(self->hmAddress,"IN:%s",request);
|
||||
return sinqHttpCheckResponse(self);
|
||||
}
|
||||
return 1;
|
||||
@ -416,6 +419,7 @@ static int SinqHttpStatus(pHistDriver self, SConnection * pCon)
|
||||
|
||||
if (pPriv->asyncRunning == 0) {
|
||||
status = sinqHttpGetPrepare(pPriv, statusdaq);
|
||||
traceIO(pPriv->hmAddress,"OUT:%s", statusdaq);
|
||||
ghttp_set_sync(pPriv->syncRequest, ghttp_async);
|
||||
ghttp_prepare(pPriv->syncRequest);
|
||||
if (status != 1) {
|
||||
@ -446,6 +450,7 @@ static int SinqHttpStatus(pHistDriver self, SConnection * pCon)
|
||||
if (status != 1) {
|
||||
return HWFault;
|
||||
}
|
||||
traceIO(pPriv->hmAddress,"IN:%s", statusdaq);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -569,6 +574,8 @@ static int SinqHttpGetHistogram(pHistDriver self, SConnection * pCon,
|
||||
snprintf(command, 255, "%s?bank=%d&start=%d&end=%d", gethm, bank,
|
||||
start, end);
|
||||
|
||||
/* printf("SinqHttpGetHistogram:%d-%d\n", start,end); */
|
||||
|
||||
status = sinqHttpGet(pPriv, command);
|
||||
if (status != 1) {
|
||||
return HWFault;
|
||||
|
1024
slsmagnet.c
1024
slsmagnet.c
File diff suppressed because it is too large
Load Diff
385
velodorn.c
385
velodorn.c
@ -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;
|
||||
}
|
58
velodorn.h
58
velodorn.h
@ -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
|
636
velodornier.c
636
velodornier.c
@ -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;
|
||||
}
|
Reference in New Issue
Block a user