- 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\
|
OBJ=psi.o buffer.o ruli.o sps.o pimotor.o charbychar.o\
|
||||||
pipiezo.o sanswave.o faverage.o spss7.o\
|
pipiezo.o sanswave.o faverage.o spss7.o\
|
||||||
amorstat.o tasinit.o ptasdrive.o tasutil.o tasscan.o swmotor.o \
|
amorstat.o tasinit.o ptasdrive.o tasutil.o tasscan.o swmotor.o \
|
||||||
polterwrite.o ecb.o frame.o el734driv.o el734dc.o ecbdriv.o \
|
polterwrite.o ecb.o frame.o \
|
||||||
ecbcounter.o el737driv.o sinqhmdriv.o tdchm.o velodorn.o \
|
el737driv.o sinqhmdriv.o tdchm.o \
|
||||||
velodornier.o sanscook.o tecsdriv.o itc4driv.o itc4.o\
|
sanscook.o tecsdriv.o itc4driv.o itc4.o\
|
||||||
bruker.o ltc11.o A1931.o eurodriv.o slsmagnet.o \
|
bruker.o ltc11.o eurodriv.o \
|
||||||
el755driv.o serial.o scontroller.o t_update.o \
|
el755driv.o serial.o scontroller.o t_update.o \
|
||||||
t_rlp.o t_conv.o el737hpdriv.o dornier2.o el734hp.o \
|
t_rlp.o t_conv.o el737hpdriv.o el734hp.o \
|
||||||
el737hpv2driv.o swmotor2.o tricssupport.o amorcomp.o \
|
el737hpv2driv.o swmotor2.o tricssupport.o amorcomp.o \
|
||||||
$(MZOBJ) amordrive.o amorset.o sinqhttp.o slsecho.o\
|
$(MZOBJ) amordrive.o amorset.o sinqhttp.o slsecho.o\
|
||||||
dgrambroadcast.o sinq.o tabledrive.o julcho.o sinqhttpopt.o\
|
dgrambroadcast.o sinq.o tabledrive.o sinqhttpopt.o\
|
||||||
ritastorage.o poldizug.o audinelib.o delcam.o el737hpdrivsps.o \
|
ritastorage.o poldizug.o el737hpdrivsps.o \
|
||||||
rebin.o sanslirebin.o lmd200.o slsvme.o julprot.o sinqhttpprot.o \
|
rebin.o sanslirebin.o lmd200.o slsvme.o julprot.o sinqhttpprot.o \
|
||||||
pmacprot.o pfeifferprot.o termprot.o phytron.o autowin.o eigera2.o \
|
pmacprot.o pfeifferprot.o termprot.o phytron.o autowin.o eigera2.o \
|
||||||
tclClock.o tclDate.o tclUnixTime.o jvlprot.o
|
tclClock.o tclDate.o tclUnixTime.o jvlprot.o epicscounter.o \
|
||||||
|
eigermono.o
|
||||||
|
|
||||||
.SECONDARY.: sanslirebin.c
|
.SECONDARY.: sanslirebin.c
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ include ../sllinux_def
|
|||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 $(NI) -I$(TCLINC) -Ihardsup \
|
CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 $(NI) -I$(TCLINC) -Ihardsup \
|
||||||
-I.. -I. -MMD -DCYGNUS -DNONINTF -g $(DFORTIFY) \
|
-I.. -I. -MMD -DCYGNUS -DNONINTF $(DBG) $(DFORTIFY) \
|
||||||
-Wall -Wno-unused -Wunused-value -Wno-comment -Wno-switch -Werror
|
-Wall -Wno-unused -Wunused-value -Wno-comment -Wno-switch -Werror
|
||||||
|
|
||||||
EXTRA=nintf.o
|
EXTRA=nintf.o
|
||||||
|
92
psi.c
92
psi.c
@ -24,15 +24,12 @@
|
|||||||
#include "site.h"
|
#include "site.h"
|
||||||
#include <motor.h>
|
#include <motor.h>
|
||||||
#include <site.h>
|
#include <site.h>
|
||||||
#include "ecbdriv.h"
|
|
||||||
#include "ecbcounter.h"
|
|
||||||
#include "sinqhmdriv.i"
|
#include "sinqhmdriv.i"
|
||||||
#include "tdchm.h"
|
#include "tdchm.h"
|
||||||
#include "tecsdriv.h"
|
#include "tecsdriv.h"
|
||||||
#include "itc4.h"
|
#include "itc4.h"
|
||||||
#include "bruker.h"
|
#include "bruker.h"
|
||||||
#include "ltc11.h"
|
#include "ltc11.h"
|
||||||
#include "A1931.h"
|
|
||||||
#include "eurodriv.h"
|
#include "eurodriv.h"
|
||||||
#include "el755driv.h"
|
#include "el755driv.h"
|
||||||
#include <evdriver.i>
|
#include <evdriver.i>
|
||||||
@ -110,10 +107,8 @@ static void AddPsiCommands(SicsInterp * pInter)
|
|||||||
SCMD("MakeAmorStatus", AmorStatusFactory);
|
SCMD("MakeAmorStatus", AmorStatusFactory);
|
||||||
SCMD("MakeECB", MakeECB);
|
SCMD("MakeECB", MakeECB);
|
||||||
SCMD("MakeFocusAverager", MakeFA);
|
SCMD("MakeFocusAverager", MakeFA);
|
||||||
SCMD("MakeJulCho", JulChoFactory);
|
|
||||||
SCMD("MakeLMD200", MakeLMD200);
|
SCMD("MakeLMD200", MakeLMD200);
|
||||||
SCMD("MakePIMotor", PIMotorFactory);
|
SCMD("MakePIMotor", PIMotorFactory);
|
||||||
SCMD("MakePoldiReiss", MakePoldiReiss);
|
|
||||||
SCMD("MakePSDFrame", MakeFrameFunc);
|
SCMD("MakePSDFrame", MakeFrameFunc);
|
||||||
SCMD("MakeRitaFix", MakeRitaFix);
|
SCMD("MakeRitaFix", MakeRitaFix);
|
||||||
SCMD("MakeRitaWin", MakeRitaWin);
|
SCMD("MakeRitaWin", MakeRitaWin);
|
||||||
@ -132,6 +127,7 @@ static void AddPsiCommands(SicsInterp * pInter)
|
|||||||
SCMD("PolterInstall", PolterInstall);
|
SCMD("PolterInstall", PolterInstall);
|
||||||
SCMD("SerialInit", SerialInit);
|
SCMD("SerialInit", SerialInit);
|
||||||
SCMD("MakeEiger", InitEiger);
|
SCMD("MakeEiger", InitEiger);
|
||||||
|
SCMD("MakeEigerMono", InitEigerMono);
|
||||||
PCMD("cnvrt", CnvrtAction);
|
PCMD("cnvrt", CnvrtAction);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -146,8 +142,6 @@ static void AddPsiCommands(SicsInterp * pInter)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
MotorDriver *CreateEL734(SConnection * pCon, int argc, char *argv[]);
|
|
||||||
MotorDriver *CreateEL734DC(SConnection * pCon, int argc, char *argv[]);
|
|
||||||
MotorDriver *CreateEL734HP(SConnection * pCon, int argc, char *argv[]);
|
MotorDriver *CreateEL734HP(SConnection * pCon, int argc, char *argv[]);
|
||||||
MotorDriver *CreateEL734HPT(SConnection * pCon, int argc, char *argv[]);
|
MotorDriver *CreateEL734HPT(SConnection * pCon, int argc, char *argv[]);
|
||||||
MotorDriver *MakePiPiezo(Tcl_Interp * pTcl, char *pArray);
|
MotorDriver *MakePiPiezo(Tcl_Interp * pTcl, char *pArray);
|
||||||
@ -173,18 +167,6 @@ static pMotor CreatePsiMotor(SConnection * pCon, int argc, char *argv[])
|
|||||||
SCWrite(pCon, pBueffel, eError);
|
SCWrite(pCon, pBueffel, eError);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else if (strcmp(argv[1], "el734") == 0) {
|
|
||||||
pDriver = (MotorDriver *) CreateEL734(pCon, argc - 2, &argv[2]);
|
|
||||||
if (!pDriver) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* create the motor */
|
|
||||||
pNew = MotorInit("EL734", argv[0], pDriver);
|
|
||||||
if (!pNew) {
|
|
||||||
snprintf(pBueffel,131, "Failure to create motor %s", argv[1]);
|
|
||||||
SCWrite(pCon, pBueffel, eError);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[1], "el734hp") == 0) {
|
} else if (strcmp(argv[1], "el734hp") == 0) {
|
||||||
pDriver = (MotorDriver *) CreateEL734HP(pCon, argc - 2, &argv[2]);
|
pDriver = (MotorDriver *) CreateEL734HP(pCon, argc - 2, &argv[2]);
|
||||||
if (!pDriver) {
|
if (!pDriver) {
|
||||||
@ -209,30 +191,6 @@ static pMotor CreatePsiMotor(SConnection * pCon, int argc, char *argv[])
|
|||||||
SCWrite(pCon, pBueffel, eError);
|
SCWrite(pCon, pBueffel, eError);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else if (strcmp(argv[1], "el734dc") == 0) {
|
|
||||||
pDriver = (MotorDriver *) CreateEL734DC(pCon, argc - 2, &argv[2]);
|
|
||||||
if (!pDriver) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* create the motor */
|
|
||||||
pNew = MotorInit("EL734DC", argv[0], pDriver);
|
|
||||||
if (!pNew) {
|
|
||||||
snprintf(pBueffel,131, "Failure to create motor %s", argv[1]);
|
|
||||||
SCWrite(pCon, pBueffel, eError);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[1], "ecb") == 0) {
|
|
||||||
pDriver = (MotorDriver *) CreateECBMotor(pCon, argc - 2, &argv[2]);
|
|
||||||
if (!pDriver) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* create the motor */
|
|
||||||
pNew = MotorInit("ECB", argv[0], pDriver);
|
|
||||||
if (!pNew) {
|
|
||||||
snprintf(pBueffel,131, "Failure to create motor %s", argv[0]);
|
|
||||||
SCWrite(pCon, pBueffel, eError);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return pNew;
|
return pNew;
|
||||||
}
|
}
|
||||||
@ -246,6 +204,8 @@ extern pCounterDriver MakeEL737HPV2(SConnection * pCon, char *name,
|
|||||||
int argc, char *argv[]);
|
int argc, char *argv[]);
|
||||||
pCounterDriver MakeEL737hpsps(SConnection * pCon, char *name,
|
pCounterDriver MakeEL737hpsps(SConnection * pCon, char *name,
|
||||||
int argc, char *argv[]);
|
int argc, char *argv[]);
|
||||||
|
|
||||||
|
pCounterDriver MakeEPICSCounter(char *rootname);
|
||||||
/*-------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------*/
|
||||||
static pCounterDriver CreatePsiCounterDriver(SConnection * pCon,
|
static pCounterDriver CreatePsiCounterDriver(SConnection * pCon,
|
||||||
int argc, char *argv[])
|
int argc, char *argv[])
|
||||||
@ -263,20 +223,17 @@ static pCounterDriver CreatePsiCounterDriver(SConnection * pCon,
|
|||||||
pNew = MakeEL737hpsps(pCon, argv[1], argc - 3, &argv[3]);
|
pNew = MakeEL737hpsps(pCon, argv[1], argc - 3, &argv[3]);
|
||||||
} else if (strcmp(argv[2], "el737hpv2") == 0) {
|
} else if (strcmp(argv[2], "el737hpv2") == 0) {
|
||||||
pNew = MakeEL737HPV2(pCon, argv[1], argc - 3, &argv[3]);
|
pNew = MakeEL737HPV2(pCon, argv[1], argc - 3, &argv[3]);
|
||||||
} else if (strcmp(argv[2], "ecb") == 0) {
|
} else if (strcmp(argv[2], "epics") == 0) {
|
||||||
if (argc < 4) {
|
if (argc < 4) {
|
||||||
SCWrite(pCon,
|
SCWrite(pCon,
|
||||||
"ERROR: insufficient no of arguments to create ECB counter",
|
"ERROR: insufficient no of arguments to create epics counter",
|
||||||
eError);
|
eError);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
pNew = MakeECBCounter(argv[3]);
|
pNew = MakeEPICSCounter(argv[3]);
|
||||||
}
|
}
|
||||||
return pNew;
|
return pNew;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------*/
|
|
||||||
extern pHistDriver MakeDelcamHM(pStringDict options); /* in delcam.c */
|
|
||||||
/*--------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------*/
|
||||||
static HistDriver *CreatePsiHistMem(char *name, pStringDict pOptions)
|
static HistDriver *CreatePsiHistMem(char *name, pStringDict pOptions)
|
||||||
{
|
{
|
||||||
@ -288,24 +245,6 @@ static HistDriver *CreatePsiHistMem(char *name, pStringDict pOptions)
|
|||||||
pNew = MakeTDCHM(pOptions);
|
pNew = MakeTDCHM(pOptions);
|
||||||
} else if (strcmp(name, "sinqhttp") == 0) {
|
} else if (strcmp(name, "sinqhttp") == 0) {
|
||||||
pNew = CreateSinqHttpDriver(pOptions);
|
pNew = CreateSinqHttpDriver(pOptions);
|
||||||
} else if (strcmp(name, "delcam") == 0) {
|
|
||||||
pNew = MakeDelcamHM(pOptions);
|
|
||||||
}
|
|
||||||
return pNew;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------*/
|
|
||||||
extern pVelSelDriv VSCreateDornierSINQ(char *name, Tcl_Interp * pTcl);
|
|
||||||
extern pVelSelDriv VSCreateDornier2003(char *name, Tcl_Interp * pTcl);
|
|
||||||
/*-------------------------------------------------------------------*/
|
|
||||||
static pVelSelDriv CreatePsiVelSelDriv(char *name, char *array,
|
|
||||||
Tcl_Interp * pTcl)
|
|
||||||
{
|
|
||||||
pVelSelDriv pNew = NULL;
|
|
||||||
if (strcmp(name, "dornier") == 0) {
|
|
||||||
pNew = VSCreateDornierSINQ(array, pTcl);
|
|
||||||
} else if (strcmp(name, "dornier2003") == 0) {
|
|
||||||
pNew = VSCreateDornier2003(array, pTcl);
|
|
||||||
}
|
}
|
||||||
return pNew;
|
return pNew;
|
||||||
}
|
}
|
||||||
@ -375,7 +314,6 @@ static void ConfigureController(char *name, pEVControl pNew,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------*/
|
||||||
extern pEVDriver CreateSLSDriv(int argc, char *argv[]);
|
|
||||||
extern pEVDriver CreateSLSVMEDriv(int argc, char *argv[]);
|
extern pEVDriver CreateSLSVMEDriv(int argc, char *argv[]);
|
||||||
/*------------------------------------------------------------------*/
|
/*------------------------------------------------------------------*/
|
||||||
|
|
||||||
@ -436,28 +374,12 @@ static pEVControl InstallPsiEnvironmentController(SicsInterp * pSics,
|
|||||||
commandInstalled = 1;
|
commandInstalled = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (strcmp(argv[3], "a1931") == 0) {
|
|
||||||
checkError = 1;
|
|
||||||
pDriv = CreateA1931Driver(argc - 4, &argv[4]);
|
|
||||||
if (pDriv != NULL) {
|
|
||||||
pNew = CreateEVController(pDriv, argv[2], &status);
|
|
||||||
if (pNew != NULL) {
|
|
||||||
AddCommand(pSics, argv[2], A1931Action, DeleteEVController, pNew);
|
|
||||||
commandInstalled = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[3], "euro") == 0) {
|
} else if (strcmp(argv[3], "euro") == 0) {
|
||||||
checkError = 1;
|
checkError = 1;
|
||||||
pDriv = CreateEURODriv(argc - 4, &argv[4]);
|
pDriv = CreateEURODriv(argc - 4, &argv[4]);
|
||||||
if (pDriv != NULL) {
|
if (pDriv != NULL) {
|
||||||
pNew = CreateEVController(pDriv, argv[2], &status);
|
pNew = CreateEVController(pDriv, argv[2], &status);
|
||||||
}
|
}
|
||||||
} else if (strcmp(argv[3], "psi-dsp") == 0) {
|
|
||||||
checkError = 1;
|
|
||||||
pDriv = CreateSLSDriv(argc - 4, &argv[4]);
|
|
||||||
if (pDriv != NULL) {
|
|
||||||
pNew = CreateEVController(pDriv, argv[2], &status);
|
|
||||||
}
|
|
||||||
} else if (strcmp(argv[3], "vme-dsp") == 0) {
|
} else if (strcmp(argv[3], "vme-dsp") == 0) {
|
||||||
checkError = 1;
|
checkError = 1;
|
||||||
pDriv = CreateSLSVMEDriv(argc - 4, &argv[4]);
|
pDriv = CreateSLSVMEDriv(argc - 4, &argv[4]);
|
||||||
@ -538,7 +460,7 @@ pSite getSite(void)
|
|||||||
sitePSI->CreateMotor = CreatePsiMotor;
|
sitePSI->CreateMotor = CreatePsiMotor;
|
||||||
sitePSI->CreateCounterDriver = CreatePsiCounterDriver;
|
sitePSI->CreateCounterDriver = CreatePsiCounterDriver;
|
||||||
sitePSI->CreateHistogramMemoryDriver = CreatePsiHistMem;
|
sitePSI->CreateHistogramMemoryDriver = CreatePsiHistMem;
|
||||||
sitePSI->CreateVelocitySelector = CreatePsiVelSelDriv;
|
sitePSI->CreateVelocitySelector = NULL;
|
||||||
sitePSI->CreateControllerDriver = CreatePsiController;
|
sitePSI->CreateControllerDriver = CreatePsiController;
|
||||||
sitePSI->InstallEnvironmentController =
|
sitePSI->InstallEnvironmentController =
|
||||||
InstallPsiEnvironmentController;
|
InstallPsiEnvironmentController;
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <ghttp.h>
|
#include <ghttp.h>
|
||||||
#include <stptok.h>
|
#include <stptok.h>
|
||||||
#include <countdriv.h>
|
#include <countdriv.h>
|
||||||
|
#include <trace.h>
|
||||||
|
|
||||||
extern char *trim(char *);
|
extern char *trim(char *);
|
||||||
/*===================================================================
|
/*===================================================================
|
||||||
@ -133,6 +134,7 @@ static int sinqHttpGet(pSinqHttp self, char *request)
|
|||||||
* try two times: a reconnect is no error
|
* try two times: a reconnect is no error
|
||||||
*/
|
*/
|
||||||
ghttp_prepare(self->syncRequest);
|
ghttp_prepare(self->syncRequest);
|
||||||
|
traceIO(self->hmAddress,"OUT:%s",request);
|
||||||
httpStatus = ghttp_process(self->syncRequest);
|
httpStatus = ghttp_process(self->syncRequest);
|
||||||
if (httpStatus != ghttp_done) {
|
if (httpStatus != ghttp_done) {
|
||||||
ghttp_close(self->syncRequest);
|
ghttp_close(self->syncRequest);
|
||||||
@ -145,6 +147,7 @@ static int sinqHttpGet(pSinqHttp self, char *request)
|
|||||||
self->errorCode = SERVERERROR;
|
self->errorCode = SERVERERROR;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
traceIO(self->hmAddress,"IN:%s",request);
|
||||||
return sinqHttpCheckResponse(self);
|
return sinqHttpCheckResponse(self);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@ -416,6 +419,7 @@ static int SinqHttpStatus(pHistDriver self, SConnection * pCon)
|
|||||||
|
|
||||||
if (pPriv->asyncRunning == 0) {
|
if (pPriv->asyncRunning == 0) {
|
||||||
status = sinqHttpGetPrepare(pPriv, statusdaq);
|
status = sinqHttpGetPrepare(pPriv, statusdaq);
|
||||||
|
traceIO(pPriv->hmAddress,"OUT:%s", statusdaq);
|
||||||
ghttp_set_sync(pPriv->syncRequest, ghttp_async);
|
ghttp_set_sync(pPriv->syncRequest, ghttp_async);
|
||||||
ghttp_prepare(pPriv->syncRequest);
|
ghttp_prepare(pPriv->syncRequest);
|
||||||
if (status != 1) {
|
if (status != 1) {
|
||||||
@ -446,6 +450,7 @@ static int SinqHttpStatus(pHistDriver self, SConnection * pCon)
|
|||||||
if (status != 1) {
|
if (status != 1) {
|
||||||
return HWFault;
|
return HWFault;
|
||||||
}
|
}
|
||||||
|
traceIO(pPriv->hmAddress,"IN:%s", statusdaq);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,6 +574,8 @@ static int SinqHttpGetHistogram(pHistDriver self, SConnection * pCon,
|
|||||||
snprintf(command, 255, "%s?bank=%d&start=%d&end=%d", gethm, bank,
|
snprintf(command, 255, "%s?bank=%d&start=%d&end=%d", gethm, bank,
|
||||||
start, end);
|
start, end);
|
||||||
|
|
||||||
|
/* printf("SinqHttpGetHistogram:%d-%d\n", start,end); */
|
||||||
|
|
||||||
status = sinqHttpGet(pPriv, command);
|
status = sinqHttpGet(pPriv, command);
|
||||||
if (status != 1) {
|
if (status != 1) {
|
||||||
return HWFault;
|
return HWFault;
|
||||||
|
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