1530 lines
42 KiB
C
1530 lines
42 KiB
C
/*---------------------------------------------------------------------------
|
|
E N V I R O N M E N T C O N T R O L L E R
|
|
|
|
This is the implementation file for a base class for all environment
|
|
control devices in SICS.
|
|
|
|
Mark Koennecke, Juli 1997
|
|
|
|
Implemented calling site specific initialisation routines.
|
|
Mark Koennecke, July 2003
|
|
|
|
Implemented scripted out of tolerance handling and retrieval of
|
|
driver name.
|
|
Mark Koennecke, December 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 <string.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <time.h>
|
|
#include <tcl.h>
|
|
#include "fortify.h"
|
|
#include "splitter.h"
|
|
#include "sics.h"
|
|
#include "obpar.h"
|
|
#include "devexec.h"
|
|
#include "nserver.h"
|
|
#include "interrupt.h"
|
|
#include "emon.h"
|
|
#include "varlog.h"
|
|
#include "evcontroller.h"
|
|
#include "evcontroller.i"
|
|
#include "evdriver.i"
|
|
#include "simev.h"
|
|
#include "tclev.h"
|
|
#include "chadapter.h"
|
|
#include "status.h"
|
|
#include "site.h"
|
|
/*--------------------- Functions needed to implement interfaces -----------*/
|
|
static long EVIDrive(void *pData, SConnection * pCon, float fVal)
|
|
{
|
|
pEVControl self = NULL;
|
|
int iRet, iCode, i, iFix, savedStatus;
|
|
char pError[132], pBueffel[256];
|
|
Tcl_Interp *pTcl = NULL;
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
assert(pCon);
|
|
|
|
if (self->runScript != NULL) {
|
|
pTcl = InterpGetTcl(pServ->pSics);
|
|
snprintf(pBueffel, sizeof(pBueffel), "%s %f", self->runScript, fVal);
|
|
iRet = Tcl_Eval(pTcl, pBueffel);
|
|
if (iRet != TCL_OK) {
|
|
SCPrintf(pCon, eError,
|
|
"ERROR: %s while processing runscript for %s",
|
|
pTcl->result, self->pName);
|
|
}
|
|
}
|
|
|
|
self->fTarget = fVal;
|
|
self->eMode = EVDrive;
|
|
self->iStop = 0;
|
|
self->start = time(NULL);
|
|
self->lastt = 0;
|
|
self->iWarned = 0;
|
|
if (self->conn != NULL) {
|
|
SCDeleteConnection(self->conn);
|
|
}
|
|
self->conn = SCCopyConnection(pCon);
|
|
if (self->conn == NULL) {
|
|
SCWrite(pCon, "ERROR: out of memory in EVIDrive", eError);
|
|
return 0;
|
|
}
|
|
|
|
/* try at least three times to do it */
|
|
for (i = 0; i < 3; i++) {
|
|
iRet = self->pDriv->SetValue(self->pDriv, fVal);
|
|
if (!iRet) {
|
|
self->pDriv->GetError(self->pDriv, &iCode, pError, 131);
|
|
iFix = self->pDriv->TryFixIt(self->pDriv, iCode);
|
|
switch (iFix) {
|
|
case DEVOK:
|
|
return 1;
|
|
break;
|
|
case DEVFAULT:
|
|
sprintf(pBueffel, "ERROR: %s", pError);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
case DEVREDO:
|
|
sprintf(pBueffel, "WARNING: Fixing problem %s", pError);
|
|
SCWrite(pCon, pBueffel, eWarning);
|
|
break;
|
|
}
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
SCWrite(pCon, "ERROR: Failed to fix previous problems, Device Error",
|
|
eError);
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static float EVIGet(void *pData, SConnection * pCon)
|
|
{
|
|
pEVControl self = NULL;
|
|
int iRet, iCode, i, iFix;
|
|
char pError[132], pBueffel[256];
|
|
float fPos = -999.;
|
|
int iPendingCount = 0;
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
assert(pCon);
|
|
|
|
/* try at least three times to do it */
|
|
for (i = 0; i < 5; i++) {
|
|
iRet = self->pDriv->GetValue(self->pDriv, &fPos);
|
|
if (iRet == 0) {
|
|
self->pDriv->GetError(self->pDriv, &iCode, pError, 131);
|
|
iFix = self->pDriv->TryFixIt(self->pDriv, iCode);
|
|
switch (iFix) {
|
|
case DEVOK:
|
|
return fPos;
|
|
break;
|
|
case DEVFAULT:
|
|
sprintf(pBueffel, "ERROR: %s", pError);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return -999.;
|
|
case DEVREDO:
|
|
sprintf(pBueffel, "WARNING: Fixing problem %s", pError);
|
|
SCWrite(pCon, pBueffel, eWarning);
|
|
break;
|
|
}
|
|
} else if (iRet == -1) { /* pending */
|
|
i--;
|
|
iPendingCount++;
|
|
if (iPendingCount > 300) {
|
|
SCWrite(pCon, "ERROR: cannot get data from socket", eError);
|
|
return -999.;
|
|
}
|
|
} else {
|
|
return fPos;
|
|
}
|
|
}
|
|
SCWrite(pCon, "ERROR: Failed to fix previous problems, Device Error",
|
|
eError);
|
|
return -999.;
|
|
}
|
|
|
|
static void notifyStatus(pEVControl self, SConnection * pCon, int status)
|
|
{
|
|
if (self->pDrivInt->drivableStatus != status) {
|
|
((SConnection *) pCon)->conEventType = STATUS;
|
|
((SConnection *) pCon)->conStatus = status;
|
|
SCWrite(pCon, "", eEvent);
|
|
self->pDrivInt->drivableStatus = status;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int EVIStatus(void *pData, SConnection * pCon)
|
|
{
|
|
pEVControl self = NULL;
|
|
float fPos, fDelta = .0;
|
|
int iRet, iCode, iFix;
|
|
char pBueffel[256], pError[132];
|
|
static int callCount;
|
|
time_t now, tmo;
|
|
float tol;
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
assert(pCon);
|
|
|
|
/* go to idle when stopped */
|
|
if (self->iStop) {
|
|
notifyStatus(self, pCon, HWIdle);
|
|
return HWIdle;
|
|
}
|
|
|
|
/* get the current position */
|
|
|
|
iRet =
|
|
self->pDriv->GetValues(self->pDriv, &self->fTarget, &fPos, &fDelta);
|
|
if (iRet == 0) {
|
|
self->pDriv->GetError(self->pDriv, &iCode, pError, 131);
|
|
iFix = self->pDriv->TryFixIt(self->pDriv, iCode);
|
|
switch (iFix) {
|
|
case DEVOK:
|
|
return HWBusy;
|
|
break;
|
|
case DEVFAULT:
|
|
sprintf(pBueffel, "ERROR: %s", pError);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
notifyStatus(self, pCon, HWFault);
|
|
return HWFault;
|
|
case DEVREDO:
|
|
sprintf(pBueffel, "WARNING: Fixing problem %s", pError);
|
|
SCWrite(pCon, pBueffel, eWarning);
|
|
notifyStatus(self, pCon, HWBusy);
|
|
return HWBusy;
|
|
break;
|
|
}
|
|
} else if (iRet == -1) { /* pending */
|
|
notifyStatus(self, pCon, HWBusy);
|
|
return HWBusy;
|
|
}
|
|
|
|
if (fPos < -990.) {
|
|
snprintf(pBueffel, 255, "ERROR: %s cannot read its current value",
|
|
self->pName);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
self->eMode = EVIdle;
|
|
notifyStatus(self, pCon, HWFault);
|
|
return HWFault;
|
|
}
|
|
|
|
if (fDelta < 0.) {
|
|
fDelta = -fDelta;
|
|
}
|
|
|
|
/* handle callback */
|
|
callCount++;
|
|
if (callCount >= 10) {
|
|
sprintf(pBueffel, "%s = %g", self->pName, fPos);
|
|
InvokeCallBack(self->pCall, VALUECHANGE, pBueffel);
|
|
callCount = 0;
|
|
}
|
|
|
|
now = time(NULL);
|
|
tmo = (int) (ObVal(self->pParam, MAXWAIT));
|
|
/* based on this: logic ! */
|
|
if (tmo > 0 && now > self->start + tmo) { /* time out */
|
|
snprintf(pBueffel,255, "ERROR: wait time limit reached on %s", self->pName);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
self->eMode = EVMonitor;
|
|
notifyStatus(self, pCon, HWIdle);
|
|
return HWIdle;
|
|
}
|
|
tol = ObVal(self->pParam, TOLERANCE);
|
|
if (self->lastt > 0) { /* increase tol for hysteresis */
|
|
tol = tol * 1.1001;
|
|
}
|
|
tmo = (int) (ObVal(self->pParam, SETTLE));
|
|
if (fDelta <= tol) { /* inside tolerance */
|
|
if (self->lastt <= 0) { /* lastt negative: -seconds already waited */
|
|
self->lastt += now;
|
|
if (tmo > 0) {
|
|
snprintf(pBueffel,255, "%s inside tolerance, wait %.2f sec to settle",
|
|
self->pName, (self->lastt + tmo - now) * 1.0);
|
|
SCWrite(pCon, pBueffel, eLog);
|
|
}
|
|
notifyStatus(self, pCon, HWBusy);
|
|
return HWBusy;
|
|
}
|
|
if (now > self->lastt + tmo) {
|
|
self->eMode = EVMonitor;
|
|
notifyStatus(self, pCon, HWIdle);
|
|
return HWIdle;
|
|
}
|
|
notifyStatus(self, pCon, HWBusy);
|
|
return HWBusy;
|
|
} else {
|
|
if (self->lastt > 0) { /* save time already waited */
|
|
if (tmo > 0) {
|
|
snprintf(pBueffel,255, "%s outside tolerance, settling time suspended",
|
|
self->pName);
|
|
SCWrite(pCon, pBueffel, eLog);
|
|
}
|
|
self->lastt -= now;
|
|
}
|
|
notifyStatus(self, pCon, HWBusy);
|
|
return HWBusy;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int EVILimits(void *pData, float fVal, char *pError, int iErrLen)
|
|
{
|
|
pEVControl self = NULL;
|
|
char pBueffel[256];
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
|
|
/* lower limit */
|
|
if (fVal < ObVal(self->pParam, LOWLIMIT)) {
|
|
sprintf(pBueffel, "ERROR: %g violates lower limit of device", fVal);
|
|
strlcpy(pError, pBueffel, iErrLen);
|
|
return 0;
|
|
}
|
|
|
|
/* upper limit */
|
|
if (fVal > ObVal(self->pParam, UPLIMIT)) {
|
|
sprintf(pBueffel, "ERROR: %g violates upper limit of device", fVal);
|
|
strlcpy(pError, pBueffel, iErrLen);
|
|
return 0;
|
|
}
|
|
|
|
/* OK */
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int EVIHalt(void *pData)
|
|
{
|
|
pEVControl self = NULL;
|
|
float fPos;
|
|
int iRet, iRes;
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
|
|
iRes = 1;
|
|
self->eMode = EVIdle;
|
|
self->iStop = 1;
|
|
|
|
return iRes;
|
|
}
|
|
|
|
/*---------------------------- Error Handlers --------------------------------*/
|
|
static void ErrWrite(char *txt, SConnection * conn)
|
|
{
|
|
pExeList pExe;
|
|
SConnection *pCon = NULL;
|
|
|
|
pExe = GetExecutor();
|
|
pCon = GetExeOwner(pExe);
|
|
|
|
if (pCon) {
|
|
SCWrite(pCon, txt, eLog);
|
|
} else {
|
|
SCWrite(conn, txt, eLog);
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static void ErrReport(pEVControl self)
|
|
{
|
|
float fPos = .0, fDelta = .0;
|
|
char pBueffel[256];
|
|
|
|
self->pDriv->GetValues(self->pDriv, &self->fTarget, &fPos, &fDelta);
|
|
if (self->iWarned == 0) {
|
|
snprintf(pBueffel, 255,"WARNING: %s is out of range by %g",
|
|
self->pName, fDelta);
|
|
ErrWrite(pBueffel, self->conn);
|
|
self->iWarned = 1;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int ErrLazy(void *pData)
|
|
{
|
|
pEVControl self = NULL;
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
|
|
ErrReport(self);
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int ErrPause(void *pData)
|
|
{
|
|
pEVControl self = NULL;
|
|
pExeList pExe;
|
|
int iRet;
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
|
|
ErrReport(self);
|
|
|
|
pExe = GetExecutor();
|
|
if (IsCounting(pExe)) {
|
|
SCWrite(GetExeOwner(pExe), "Pausing till OK", eLogError);
|
|
PauseExecution(pExe);
|
|
|
|
/* wait till OK */
|
|
iRet = 0;
|
|
while (iRet == 0 && IsCounting(pExe)) {
|
|
SicsWait(5);
|
|
iRet = self->pEnvir->IsInTolerance(self);
|
|
}
|
|
|
|
/* OK now, continue */
|
|
self->iWarned = 0;
|
|
ContinueExecution(pExe);
|
|
return 1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int ErrScript(void *pData)
|
|
{
|
|
pEVControl self = NULL;
|
|
int iRet;
|
|
Tcl_Interp *pTcl = NULL;
|
|
pExeList pExe;
|
|
char pBueffel[256];
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
|
|
ErrReport(self);
|
|
|
|
pExe = GetExecutor();
|
|
if (self->errorScript != NULL) {
|
|
pTcl = InterpGetTcl(pServ->pSics);
|
|
iRet = Tcl_Eval(pTcl, self->errorScript);
|
|
if (iRet != TCL_OK) {
|
|
snprintf(pBueffel, 255,
|
|
"ERROR: %s while processing errorscript for %s",
|
|
pTcl->result, self->pName);
|
|
ErrWrite(pBueffel, self->conn);
|
|
}
|
|
/*
|
|
assume that everything is fine again after the script
|
|
returns
|
|
*/
|
|
self->eMode = EVMonitor;
|
|
self->iWarned = 0;
|
|
} else {
|
|
snprintf(pBueffel, 255,
|
|
"ERROR: script error handling requested for %s, but no script given",
|
|
self->pName);
|
|
ErrWrite(pBueffel, self->conn);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int ErrInterrupt(void *pData)
|
|
{
|
|
pEVControl self = NULL;
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
|
|
ErrReport(self);
|
|
|
|
/* interrupt */
|
|
SetInterrupt((int) ObVal(self->pParam, INTERRUPT));
|
|
self->iWarned = 0;
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int ErrRun(void *pData)
|
|
{
|
|
pEVControl self = NULL;
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
|
|
ErrReport(self);
|
|
|
|
ErrWrite("Running to safe value", self->conn);
|
|
self->pDriv->SetValue(self->pDriv, ObVal(self->pParam, SAFEVALUE));
|
|
self->eMode = EVIdle;
|
|
self->iWarned = 0;
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static int EVIErrHandler(void *pData)
|
|
{
|
|
pEVControl self = NULL;
|
|
int iRet, iHandler, iStatus;
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
|
|
/* select an error handler according to the variable set
|
|
in Controller
|
|
*/
|
|
iHandler = (int) ObVal(self->pParam, ERRORHANDLER);
|
|
self->eMode = EVError;
|
|
switch (iHandler) {
|
|
case 0: /* no op */
|
|
iStatus = ErrLazy(pData);
|
|
break;
|
|
case 1: /* Pause */
|
|
iStatus = ErrPause(pData);
|
|
break;
|
|
case 2: /* Interrupt */
|
|
iStatus = ErrInterrupt(pData);
|
|
break;
|
|
case 3: /* run to a safe place, put him into idle afterwards */
|
|
iStatus = ErrRun(pData);
|
|
return iStatus;
|
|
break;
|
|
case 4: /* invoke a script */
|
|
iStatus = ErrScript(pData);
|
|
return iStatus;
|
|
break;
|
|
default:
|
|
return 0;
|
|
|
|
}
|
|
/* reset mode to monitor again! */
|
|
self->eMode = EVMonitor;
|
|
return iStatus;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
static EVMode EVIGetMode(void *pData)
|
|
{
|
|
pEVControl self = NULL;
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
|
|
return self->eMode;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int EVIIsInTolerance(void *pData)
|
|
{
|
|
pEVControl self = NULL;
|
|
float fPos, fDelta;
|
|
int iRet, iCode, iStat;
|
|
char pError[132], pBueffel[512];
|
|
pExeList pExe = NULL;
|
|
SConnection *pCon = NULL;
|
|
float tol;
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
|
|
|
|
iRet =
|
|
self->pDriv->GetValues(self->pDriv, &self->fTarget, &fPos, &fDelta);
|
|
if (iRet == 1) {
|
|
if (self->iLog) {
|
|
VarlogAdd(self->pLog, fPos);
|
|
}
|
|
if (fDelta < 0.) {
|
|
fDelta = -fDelta;
|
|
}
|
|
tol = ObVal(self->pParam, TOLERANCE);
|
|
if (self->iWarned == 0)
|
|
tol = tol * 1.1001;
|
|
if (fDelta <= tol) {
|
|
self->eMode = EVMonitor;
|
|
if (self->iWarned) {
|
|
snprintf(pBueffel,255, "Environment device %s back in tolerances again",
|
|
self->pName);
|
|
ErrWrite(pBueffel, self->conn);
|
|
self->iWarned = 0;
|
|
}
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
/* deal with callbacks */
|
|
self->callCount++;
|
|
if (self->callCount >= 20) {
|
|
snprintf(pBueffel,255, "%s = %g", self->pName, fPos);
|
|
InvokeCallBack(self->pCall, VALUECHANGE, pBueffel);
|
|
self->callCount = 0;
|
|
}
|
|
} else if (iRet == -1) { /* pending */
|
|
/* pending means OK to me */
|
|
return 1;
|
|
} else {
|
|
/* break down of connection to a environment device has to be
|
|
considered a problem as well
|
|
*/
|
|
memset(pError, 0, 132 * sizeof(char));
|
|
self->pDriv->GetError(self->pDriv, &iCode, pError, 131);
|
|
Log(ERROR,"dev", "emon:%s", pError);
|
|
iStat = self->pDriv->TryFixIt(self->pDriv, iCode);
|
|
if ((iStat == DEVOK) || (iStat == DEVREDO)) {
|
|
return 1; /* effectively a redo in some time */
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static void *EVIInterface(void *pData, int iCode)
|
|
{
|
|
pEVControl self = NULL;
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
|
|
if (iCode == DRIVEID) {
|
|
return self->pDrivInt;
|
|
} else if (iCode == ENVIRINTERFACE) {
|
|
return self->pEnvir;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* this routine is the standard method of pEVDriver for GetValues.
|
|
* it may be replaced by a device specific routine, for the case that
|
|
* the target value differs systematically from the target value
|
|
* (i.e.control not on sample sensor)
|
|
* Oct. 2002 M.Zolliker
|
|
*/
|
|
static int StdGetValues(pEVDriver self, float *fTarget, float *fPos,
|
|
float *fDelta)
|
|
{
|
|
int iRet;
|
|
|
|
assert(self);
|
|
iRet = self->GetValue(self, fPos);
|
|
if (iRet > 0)
|
|
*fDelta = *fTarget - *fPos;
|
|
return iRet;
|
|
}
|
|
|
|
/*-------- All this done, we can actually implement the controller ---------*/
|
|
pEVControl CreateEVController(pEVDriver pDriv, char *pName, int *iErr)
|
|
{
|
|
pEVControl pRes = NULL;
|
|
int iRet;
|
|
|
|
assert(pDriv);
|
|
*iErr = 1;
|
|
|
|
/* new memory first */
|
|
pRes = (pEVControl) malloc(sizeof(EVControl));
|
|
if (!pRes) {
|
|
return NULL;
|
|
}
|
|
memset(pRes, 0, sizeof(EVControl));
|
|
|
|
/* new Object Descriptor */
|
|
pRes->pDes = CreateDescriptor("Environment Controller");
|
|
if (!pRes->pDes) {
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
pRes->pDes->GetInterface = EVIInterface;
|
|
|
|
/* new Drivable interface */
|
|
pRes->pDrivInt = CreateDrivableInterface();
|
|
if (!pRes->pDrivInt) {
|
|
DeleteDescriptor(pRes->pDes);
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
pRes->pDrivInt->Halt = EVIHalt;
|
|
pRes->pDrivInt->CheckLimits = EVILimits;
|
|
pRes->pDrivInt->SetValue = EVIDrive;
|
|
pRes->pDrivInt->CheckStatus = EVIStatus;
|
|
pRes->pDrivInt->GetValue = EVIGet;
|
|
|
|
|
|
/* new environment interface */
|
|
pRes->pEnvir = CreateEVInterface();
|
|
if (!pRes->pEnvir) {
|
|
free(pRes->pDrivInt);
|
|
DeleteDescriptor(pRes->pDes);
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
pRes->pEnvir->GetMode = EVIGetMode;
|
|
pRes->pEnvir->IsInTolerance = EVIIsInTolerance;
|
|
pRes->pEnvir->HandleError = EVIErrHandler;
|
|
|
|
/* callback interface */
|
|
pRes->pCall = CreateCallBackInterface();
|
|
if (!pRes->pCall) {
|
|
free(pRes->pDrivInt);
|
|
DeleteDescriptor(pRes->pDes);
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
|
|
/* new parameter space */
|
|
pRes->pParam = ObParCreate(9);
|
|
if (!pRes->pParam) {
|
|
free(pRes->pDrivInt);
|
|
free(pRes->pEnvir);
|
|
DeleteDescriptor(pRes->pDes);
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
ObParInit(pRes->pParam, TOLERANCE, "tolerance", 2.0, usUser);
|
|
ObParInit(pRes->pParam, ACCESS, "access", usUser, usMugger);
|
|
ObParInit(pRes->pParam, ERRORHANDLER, "errorhandler", 0.0, usUser);
|
|
ObParInit(pRes->pParam, INTERRUPT, "interrupt", eContinue, usUser);
|
|
ObParInit(pRes->pParam, UPLIMIT, "upperlimit", 300.0, usUser);
|
|
ObParInit(pRes->pParam, LOWLIMIT, "lowerlimit", 1.0, usUser);
|
|
ObParInit(pRes->pParam, SAFEVALUE, "safevalue", 0., usUser);
|
|
ObParInit(pRes->pParam, MAXWAIT, "maxwait", 0., usUser);
|
|
ObParInit(pRes->pParam, SETTLE, "settle", 0., usUser);
|
|
|
|
/* local initialisations */
|
|
if (pDriv->GetValues == NULL) { /* if GetValues is undefined, set to default */
|
|
pDriv->GetValues = StdGetValues;
|
|
}
|
|
iRet = pDriv->Init(pDriv);
|
|
|
|
*iErr = iRet;
|
|
|
|
/* new var log for logging values */
|
|
pRes->iLog = 1;
|
|
if (!VarlogInit(&pRes->pLog)) {
|
|
DeleteEVController(pRes);
|
|
return NULL;
|
|
}
|
|
|
|
pRes->pName = strdup(pName);
|
|
pRes->eMode = EVIdle;
|
|
pRes->iWarned = 0;
|
|
if (pRes->conn != NULL) {
|
|
SCDeleteConnection(pRes->conn);
|
|
pRes->conn = NULL;
|
|
}
|
|
|
|
/* a terminal error gives a -1 in iRet */
|
|
if (iRet < 0) {
|
|
DeleteEVController(pRes);
|
|
return NULL;
|
|
}
|
|
pRes->pDriv = pDriv; /* moved here to avoid double freeing on evfactory del */
|
|
return pRes;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
void DeleteEVController(void *pData)
|
|
{
|
|
pEVControl self = NULL;
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
|
|
if (self->pDes) {
|
|
DeleteDescriptor(self->pDes);
|
|
self->pDes = NULL;
|
|
}
|
|
if (self->pDrivInt) {
|
|
free(self->pDrivInt);
|
|
}
|
|
if (self->pEnvir) {
|
|
free(self->pEnvir);
|
|
}
|
|
if (self->pCall) {
|
|
DeleteCallBackInterface(self->pCall);
|
|
}
|
|
if (self->KillPrivate) {
|
|
self->KillPrivate(self->pPrivate);
|
|
}
|
|
if (self->pDriv) {
|
|
self->pDriv->Close(self->pDriv);
|
|
DeleteEVDriver(self->pDriv);
|
|
}
|
|
if (self->pName) {
|
|
free(self->pName);
|
|
}
|
|
if (self->pParam) {
|
|
ObParDelete(self->pParam);
|
|
}
|
|
if (self->pLog) {
|
|
VarlogDelete(self->pLog);
|
|
}
|
|
if (self->driverName != NULL) {
|
|
free(self->driverName);
|
|
}
|
|
if (self->errorScript != NULL) {
|
|
free(self->errorScript);
|
|
}
|
|
if (self->creationArgs != NULL) {
|
|
free(self->creationArgs);
|
|
}
|
|
if (self->runScript != NULL) {
|
|
free(self->runScript);
|
|
}
|
|
if (self->conn != NULL) {
|
|
SCDeleteConnection(self->conn);
|
|
}
|
|
free(self);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int EVCDrive(pEVControl self, SConnection * pCon, float fVal)
|
|
{
|
|
char pBueffel[256], pError[132];
|
|
int iRet;
|
|
|
|
assert(self);
|
|
assert(pCon);
|
|
|
|
/* Check Limits */
|
|
iRet = self->pDrivInt->CheckLimits(self, fVal, pError, 131);
|
|
if (!iRet) {
|
|
SCWrite(pCon, pError, eError);
|
|
return 0;
|
|
}
|
|
|
|
/* start executing */
|
|
iRet = StartDevice(GetExecutor(), self->pName, self->pDes,
|
|
self, pCon, SCGetRunLevel(pCon), fVal);
|
|
if (!iRet) {
|
|
snprintf(pBueffel,255, "ERROR: Failure to start %s", self->pName);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
|
|
/* Wait for success */
|
|
iRet = Wait4Success(GetExecutor());
|
|
if (iRet == DEVINT) {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int EVCGetPos(pEVControl self, SConnection * pCon, float *fPos)
|
|
{
|
|
float fVal;
|
|
|
|
assert(self);
|
|
assert(pCon);
|
|
|
|
fVal = self->pDrivInt->GetValue(self, pCon);
|
|
if (fVal < -990) {
|
|
return 0;
|
|
}
|
|
*fPos = fVal;
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
pVarLog EVCGetVarLog(pEVControl self)
|
|
{
|
|
|
|
assert(self);
|
|
|
|
return self->pLog;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
EVMode EVCGetMode(pEVControl self)
|
|
{
|
|
assert(self);
|
|
return self->eMode;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int EVCSetMode(pEVControl self, EVMode eNew)
|
|
{
|
|
assert(self);
|
|
self->eMode = eNew;
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int EVCGetPar(pEVControl self, char *name, float *fVal)
|
|
{
|
|
ObPar *pPar = NULL;
|
|
assert(self);
|
|
|
|
|
|
if (strcmp(name, "target") == 0) {
|
|
*fVal = self->fTarget;
|
|
return 1;
|
|
}
|
|
|
|
pPar = ObParFind(self->pParam, name);
|
|
if (pPar) {
|
|
*fVal = pPar->fVal;
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int EVCSetPar(pEVControl self, char *name, float fVal, SConnection * pCon)
|
|
{
|
|
ObPar *pPar = NULL;
|
|
int iRet, savedStatus;
|
|
|
|
assert(self);
|
|
assert(pCon);
|
|
|
|
/* find the parameter */
|
|
pPar = ObParFind(self->pParam, name);
|
|
if (pPar == NULL) {
|
|
SCPrintf(pCon, eError, "ERROR: %s.%s parameter not found",
|
|
self->pName, name);
|
|
return 0;
|
|
}
|
|
|
|
/* DO NOT CHECK RUNNING STATE, this is not needed */
|
|
|
|
/* check permission */
|
|
if (!SCMatchRights(pCon, pPar->iCode)) {
|
|
SCPrintf(pCon, eError, "ERROR: Insufficient privilege to change %s.%s",
|
|
self->pName, name);
|
|
return 0;
|
|
}
|
|
|
|
/* passed all tests: do It! */
|
|
pPar->fVal = fVal;
|
|
|
|
iRet = 1;
|
|
if (self->iTcl) {
|
|
iRet = UpdateTclVariable(self->pDriv, name, fVal);
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int EVCList(pEVControl self, SConnection * pCon)
|
|
{
|
|
char pBueffel[256];
|
|
float fPos;
|
|
|
|
assert(self);
|
|
assert(pCon);
|
|
|
|
snprintf(pBueffel, 255, "Parameter listing for %s", self->pName);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
|
|
snprintf(pBueffel, 255, "%s.%s = %g ", self->pName, "tolerance",
|
|
ObVal(self->pParam, TOLERANCE));
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
snprintf(pBueffel, 255, "%s.%s = %g", self->pName, "access",
|
|
ObVal(self->pParam, ACCESS));
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
snprintf(pBueffel, 255, "%s.%s = %g", self->pName, "ErrorHandler",
|
|
ObVal(self->pParam, ERRORHANDLER));
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
snprintf(pBueffel, 255, "%s.%s = %g", self->pName, "interrupt",
|
|
ObVal(self->pParam, INTERRUPT));
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
snprintf(pBueffel, 255, "%s.%s = %g", self->pName, "UpperLimit",
|
|
ObVal(self->pParam, UPLIMIT));
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
snprintf(pBueffel, 255, "%s.%s = %g", self->pName, "LowerLimit",
|
|
ObVal(self->pParam, LOWLIMIT));
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
snprintf(pBueffel, 255, "%s.%s = %g", self->pName, "SafeValue",
|
|
ObVal(self->pParam, SAFEVALUE));
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
snprintf(pBueffel, 255, "%s.%s = %g (sec)", self->pName, "MaxWait",
|
|
ObVal(self->pParam, MAXWAIT));
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
snprintf(pBueffel, 255, "%s.%s = %g (sec)", self->pName, "Settle",
|
|
ObVal(self->pParam, SETTLE));
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
EVCGetPos(self, pCon, &fPos);
|
|
snprintf(pBueffel, 255, "%s.%s = %g", self->pName, "CurrentValue", fPos);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
snprintf(pBueffel, 255, "%s.%s = %g", self->pName, "TargetValue",
|
|
self->fTarget);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
snprintf(pBueffel, 255, "%s.driver = %s", self->pName, self->driverName);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
if (self->errorScript != NULL) {
|
|
snprintf(pBueffel, 255, "%s.errorScript = %s", self->pName,
|
|
self->errorScript);
|
|
} else {
|
|
snprintf(pBueffel, 255, "%s.errorScript = UNDEFINED", self->pName);
|
|
}
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
if (self->runScript != NULL) {
|
|
SCPrintf(pCon, eValue, "%s.runScript = %s", self->pName,
|
|
self->runScript);
|
|
} else {
|
|
SCPrintf(pCon, eValue, "%s.runScript = none", self->pName);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int EVCallBack(int iEvent, void *pEventData, void *pUserData)
|
|
{
|
|
char *pBuf = (char *) pEventData;
|
|
SConnection *pCon = (SConnection *) pUserData;
|
|
char pBueffel[132];
|
|
|
|
if (pCon == NULL || !SCisConnected(pCon)) {
|
|
return -1;
|
|
}
|
|
|
|
if (iEvent == VALUECHANGE && pCon != NULL) {
|
|
SCSetEventType(pCon,POSITION);
|
|
SCWrite(pCon, pBuf, eEvent);
|
|
return 1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
The wrapper understands the following syntax:
|
|
EVControl : print current value
|
|
EVControl fVal : drive value
|
|
EVControl par : print parameter
|
|
EVControl par fVal : set parameter
|
|
EVControl list : lists parameters
|
|
EVControl log ... : log subcommands
|
|
EVControl send bla bla ..... : sends everything after
|
|
send to the device
|
|
---------------------------------------------------------------------------*/
|
|
int EVControlWrapper(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pEVControl self = NULL;
|
|
char pBueffel[256], pReply[512];
|
|
double dVal;
|
|
float fPos;
|
|
int iRet;
|
|
long lID;
|
|
|
|
self = (pEVControl) pData;
|
|
assert(self);
|
|
assert(pSics);
|
|
assert(pCon);
|
|
|
|
if (argc < 2) { /* only value requested */
|
|
iRet = EVCGetPos(self, pCon, &fPos);
|
|
if (iRet) {
|
|
/*
|
|
sprintf(pBueffel,"%s.%s = %g",self->pName,"CurrentValue", fPos);
|
|
SCWrite(pCon,pBueffel,eValue);
|
|
*/
|
|
SCPrintf(pCon, eValue, "%s = %g", argv[0], fPos);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
} else {
|
|
strtolower(argv[1]);
|
|
}
|
|
|
|
/* analyse commands */
|
|
if (strcmp(argv[1], "send") == 0) { /* send to controller */
|
|
Arg2Text(argc - 2, &argv[2], pBueffel, 255);
|
|
iRet = self->pDriv->Send(self->pDriv, pBueffel, pReply, 511);
|
|
SCWrite(pCon, pReply, eValue);
|
|
return iRet;
|
|
}
|
|
/* install automatic notification */
|
|
else if (strcmp(argv[1], "interest") == 0) {
|
|
lID = RegisterCallback(self->pCall,
|
|
VALUECHANGE, EVCallBack,
|
|
SCCopyConnection(pCon), SCDeleteConnection);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else if (strcmp(argv[1], "uninterest") == 0) {
|
|
RemoveCallbackCon(self->pCall, pCon);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else if (strcmp(argv[1], "log") == 0) { /* log commands */
|
|
if (argc < 3) {
|
|
SCWrite(pCon, "ERROR: insufficient number of commands for varlog",
|
|
eError);
|
|
return 0;
|
|
}
|
|
iRet = VarlogWrapper(self->pLog, pCon, argv[2], argv[3], argv[0]);
|
|
return iRet;
|
|
} else if (argc < 3) { /* either parameter or drive */
|
|
iRet = Tcl_GetDouble(pSics->pTcl, argv[1], &dVal);
|
|
if (iRet == TCL_OK) { /* float Value: drive */
|
|
if (!SCMatchRights(pCon, usUser)) {
|
|
return 0;
|
|
}
|
|
iRet = EVCDrive(self, pCon, (float) dVal);
|
|
if (iRet) {
|
|
SCSendOK(pCon);
|
|
}
|
|
return iRet;
|
|
} else if (strcmp(argv[1], "list") == 0) {
|
|
EVCList(self, pCon);
|
|
return 1;
|
|
} else if (strcmp(argv[1], "send") == 0) { /* send to controller */
|
|
Arg2Text(argc - 2, &argv[2], pBueffel, 255);
|
|
iRet = self->pDriv->Send(self->pDriv, pBueffel, pReply, 511);
|
|
SCWrite(pCon, pReply, eValue);
|
|
return iRet;
|
|
} else if (strcmp(argv[1], "log") == 0) { /* log commands */
|
|
if (argc < 3) {
|
|
SCWrite(pCon, "ERROR: insufficient number of commands for varlog",
|
|
eError);
|
|
return 0;
|
|
}
|
|
return VarlogWrapper(self->pLog, pCon, argv[2], argv[3], argv[0]);
|
|
} else { /* parameter request */
|
|
|
|
strtolower(argv[1]);
|
|
/*
|
|
catch case of errorScript
|
|
*/
|
|
if (strcmp(argv[1], "errorscript") == 0) {
|
|
if (self->errorScript != NULL) {
|
|
snprintf(pBueffel, 255, "%s.errorScript = %s", self->pName,
|
|
self->errorScript);
|
|
} else {
|
|
snprintf(pBueffel, 255, "%s.errorScript = UNDEFINED",
|
|
self->pName);
|
|
}
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
}
|
|
/*
|
|
catch case of runScript
|
|
*/
|
|
if (strcmp(argv[1], "runscript") == 0) {
|
|
if (self->runScript != NULL) {
|
|
SCPrintf(pCon, eValue, "%s.runScript = %s", self->pName,
|
|
self->runScript);
|
|
} else {
|
|
SCPrintf(pCon, eValue, "%s.runScript = none", self->pName);
|
|
}
|
|
return 1;
|
|
}
|
|
/*
|
|
catch case for drivername
|
|
*/
|
|
if (strcmp(argv[1], "driver") == 0) {
|
|
snprintf(pBueffel, 255, "%s.driver = %s", self->pName,
|
|
self->driverName);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
}
|
|
iRet = EVCGetPar(self, argv[1], &fPos);
|
|
if (!iRet) {
|
|
snprintf(pBueffel,255, "ERROR: parameter %s NOT found", argv[1]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
} else {
|
|
snprintf(pBueffel,255, "%s.%s = %g", self->pName, argv[1], fPos);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
}
|
|
}
|
|
} else { /* try to set parameter */
|
|
|
|
strtolower(argv[1]);
|
|
/*
|
|
first catch case of errorScript
|
|
*/
|
|
if (strcmp(argv[1], "errorscript") == 0) {
|
|
if (self->errorScript != NULL) {
|
|
free(self->errorScript);
|
|
}
|
|
self->errorScript = Arg2Tcl(argc - 2, &argv[2], NULL, 0);
|
|
SCSendOK(pCon);
|
|
SCparChange(pCon);
|
|
return 1;
|
|
}
|
|
/*
|
|
catch case of runScript
|
|
*/
|
|
if (strcmp(argv[1], "runscript") == 0) {
|
|
if (self->runScript != NULL) {
|
|
free(self->runScript);
|
|
}
|
|
if (strcasecmp(argv[2], "none") == 0) {
|
|
self->runScript = NULL;
|
|
} else {
|
|
self->runScript = Arg2Tcl(argc - 2, &argv[2], NULL, 0);
|
|
}
|
|
SCSendOK(pCon);
|
|
SCparChange(pCon);
|
|
return 1;
|
|
}
|
|
iRet = Tcl_GetDouble(pSics->pTcl, argv[2], &dVal);
|
|
if (iRet != TCL_OK) {
|
|
snprintf(pBueffel, 255,"ERROR: %s no valid number", argv[2]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
iRet = EVCSetPar(self, argv[1], (float) dVal, pCon);
|
|
if (iRet) {
|
|
SCSendOK(pCon);
|
|
SCparChange(pCon);
|
|
}
|
|
return iRet;
|
|
}
|
|
return 0; /* not reached */
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static int EVSaveStatus(void *pData, char *name, FILE * fil)
|
|
{
|
|
pEVControl evc = pData;
|
|
pEVDriver pD = evc->pDriv;
|
|
|
|
assert(evc);
|
|
assert(pD);
|
|
if (evc->creationArgs && pD->SavePars) {
|
|
fprintf(fil, "if {[catch { evfactory replace %s %s }] == 0} {\n", name,
|
|
evc->creationArgs);
|
|
if (pD->SavePars(pD, fil) == 1) {
|
|
fprintf(fil, " %s %s %g\n", evc->pName, "tolerance",
|
|
ObVal(evc->pParam, TOLERANCE));
|
|
fprintf(fil, " %s %s %g\n", evc->pName, "access",
|
|
ObVal(evc->pParam, ACCESS));
|
|
fprintf(fil, " %s %s %g\n", evc->pName, "ErrorHandler",
|
|
ObVal(evc->pParam, ERRORHANDLER));
|
|
fprintf(fil, " %s %s %g\n", evc->pName, "interrupt",
|
|
ObVal(evc->pParam, INTERRUPT));
|
|
fprintf(fil, " %s %s %g\n", evc->pName, "UpperLimit",
|
|
ObVal(evc->pParam, UPLIMIT));
|
|
fprintf(fil, " %s %s %g\n", evc->pName, "LowerLimit",
|
|
ObVal(evc->pParam, LOWLIMIT));
|
|
fprintf(fil, " %s %s %g\n", evc->pName, "SafeValue",
|
|
ObVal(evc->pParam, SAFEVALUE));
|
|
fprintf(fil, " %s %s %g\n", evc->pName, "MaxWait",
|
|
ObVal(evc->pParam, MAXWAIT));
|
|
fprintf(fil, " %s %s %g\n", evc->pName, "Settle",
|
|
ObVal(evc->pParam, SETTLE));
|
|
if (evc->errorScript != NULL) {
|
|
fprintf(fil, " %s errorScript %s\n", evc->pName,
|
|
evc->errorScript);
|
|
}
|
|
if (evc->runScript != NULL) {
|
|
fprintf(fil, " %s runScript %s\n", evc->pName, evc->runScript);
|
|
}
|
|
}
|
|
fprintf(fil, "}\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* standard method for saving parameters */
|
|
static int EVCSaveStd(void *pData, char *name, FILE * fil)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
pEVControl MakeEVController(pEVDriver pDriv, SConnection * pCon,
|
|
ObjectFunc wrapper, int argc, char *argv[])
|
|
{
|
|
pEVControl pNew;
|
|
int status = 1;
|
|
char pBueffel[512];
|
|
char pError[132];
|
|
|
|
if (pDriv == NULL) {
|
|
SCWrite(pCon, "ERROR: failed to create driver", eError);
|
|
return NULL;
|
|
}
|
|
pNew = CreateEVController(pDriv, argv[0], &status);
|
|
if (status != 1) {
|
|
printf("CEVC error\n");
|
|
SCWrite(pCon, "ERROR: failed to initialize device", eError);
|
|
pDriv->GetError(pDriv, &status, pError, sizeof pError - 1);
|
|
printf("HW %s\n", pError);
|
|
sprintf(pBueffel, "HW reported: %s", pError);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
}
|
|
if (pNew == NULL) {
|
|
printf("CEVC failed\n");
|
|
SCWrite(pCon, "ERROR: failed to create environment device object",
|
|
eError);
|
|
DeleteEVDriver(pDriv);
|
|
return NULL;
|
|
}
|
|
if (wrapper == NULL) {
|
|
AddCommand(pServ->pSics, argv[0], EVControlWrapper, DeleteEVController,
|
|
pNew);
|
|
} else {
|
|
AddCommand(pServ->pSics, argv[0], wrapper, DeleteEVController, pNew);
|
|
}
|
|
return pNew;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static pEVControl InstallCommonControllers(SicsInterp * pSics,
|
|
SConnection * pCon,
|
|
int argc, char *argv[],
|
|
int *found)
|
|
{
|
|
pEVControl pNew = NULL;
|
|
pEVDriver pDriv = NULL;
|
|
char pBueffel[512], pError[132];
|
|
int iRet;
|
|
int (*Wrapper) (SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[]) = EVControlWrapper;
|
|
|
|
*found = 1;
|
|
if (strcmp(argv[3], "sim") == 0) { /* SIM driver */
|
|
/* Create a Sim Driver */
|
|
pDriv = CreateSIMEVDriver(argc - 4, &argv[4]);
|
|
if (!pDriv) {
|
|
SCWrite(pCon,
|
|
"ERROR: failed to create Environment Device driver", eError);
|
|
return NULL;
|
|
}
|
|
} else if (strcmp(argv[3], "tcl") == 0) { /* Tcl driver */
|
|
/* Create a Tcl driver */
|
|
pDriv = CreateTclDriver(argc - 4, &argv[4], argv[2], pCon);
|
|
if (!pDriv) {
|
|
SCWrite(pCon, "ERROR: failed to create TCL device driver", eError);
|
|
return NULL;
|
|
}
|
|
/* got a driver, initialise everything */
|
|
pNew = CreateEVController(pDriv, argv[2], &iRet);
|
|
if (!pNew) {
|
|
SCWrite(pCon, "ERROR creating Environment Controller", eError);
|
|
DeleteEVDriver(pDriv);
|
|
return NULL;
|
|
}
|
|
if (!iRet) {
|
|
SCWrite(pCon, "ERROR: problem initialising Environment controller",
|
|
eError);
|
|
pDriv->GetError(pDriv, &iRet, pError, 131);
|
|
sprintf(pBueffel, "HW reported: %s", pError);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
}
|
|
Wrapper = TclEnvironmentWrapper;
|
|
pNew->iTcl = 1;
|
|
/* make ev parameters available to Tcl */
|
|
UpdateTclVariable(pNew->pDriv, "tolerance",
|
|
ObVal(pNew->pParam, TOLERANCE));
|
|
UpdateTclVariable(pNew->pDriv, "upperlimit",
|
|
ObVal(pNew->pParam, UPLIMIT));
|
|
UpdateTclVariable(pNew->pDriv, "lowerlimit",
|
|
ObVal(pNew->pParam, LOWLIMIT));
|
|
} else if (strcmp(argv[3], "gencon") == 0) { /* general controller */
|
|
/* Create a driver */
|
|
pDriv = MakeControllerEnvironmentDriver(argc - 4, &argv[4]);
|
|
if (!pDriv) {
|
|
SCWrite(pCon,
|
|
"ERROR: failed to create Controller Environment driver",
|
|
eError);
|
|
return NULL;
|
|
}
|
|
} else {
|
|
/* not recognized */
|
|
*found = 0;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
if (pNew == NULL) { /* not yet initialized */
|
|
pNew = CreateEVController(pDriv, argv[2], &iRet);
|
|
if (!pNew) {
|
|
SCWrite(pCon, "ERROR creating Environment Controller", eError);
|
|
DeleteEVDriver(pDriv);
|
|
return NULL;
|
|
}
|
|
if (!iRet) {
|
|
SCWrite(pCon, "ERROR: problem initialising Environment controller",
|
|
eError);
|
|
pDriv->GetError(pDriv, &iRet, pError, 131);
|
|
sprintf(pBueffel, "HW reported: %s", pError);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
}
|
|
}
|
|
|
|
/* install command */
|
|
iRet = AddCommand(pSics, argv[2], Wrapper, DeleteEVController, pNew);
|
|
if (!iRet) {
|
|
snprintf(pBueffel,511, "ERROR: duplicate command %s not created", argv[2]);
|
|
DeleteEVController((void *) pNew);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return NULL;
|
|
}
|
|
return pNew;
|
|
}
|
|
|
|
int RemoveEVController(SConnection * pCon, char *name)
|
|
{
|
|
char pBueffel[512];
|
|
int iRet;
|
|
|
|
if (!pServ->pExecutor) {
|
|
return 1;
|
|
}
|
|
if (isInRunMode(pServ->pExecutor)) {
|
|
SCWrite(pCon, "ERROR: cannot delete while running", eError);
|
|
return 0;
|
|
}
|
|
EVUnregister(FindEMON(pServ->pSics), name);
|
|
iRet = RemoveCommand(pServ->pSics, name);
|
|
if (!iRet) {
|
|
snprintf(pBueffel,511, "ERROR: %s not found, NOT deleted", name);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
EVControlFactory implements a SICS command which creates and deletes
|
|
Controllers at run-time. Syntax:
|
|
|
|
ControlFactory new name SIM
|
|
-- creates a new controller name with a simulation driver
|
|
ControlFactory del name
|
|
-- deletes controller name
|
|
-------------------------------------------------------------------------*/
|
|
int EVControlFactory(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pEVControl pNew = NULL;
|
|
char pBueffel[512], pError[132];
|
|
int iRet, found;
|
|
CommandList *pCom = NULL;
|
|
pSite site = NULL;
|
|
|
|
assert(pSics);
|
|
assert(pCon);
|
|
|
|
if (argc < 3) {
|
|
SCWrite(pCon, "ERROR: Insufficient number of arguments to EVFactory",
|
|
eError);
|
|
return 0;
|
|
}
|
|
|
|
/* check rights */
|
|
if (!SCMatchRights(pCon, usUser)) {
|
|
return 0;
|
|
}
|
|
|
|
strtolower(argv[1]);
|
|
if (strcmp(argv[1], "del") == 0) { /* delete */
|
|
if (RemoveEVController(pCon, argv[2])) {
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else if (strcmp(argv[1], "new") == 0
|
|
|| strcmp(argv[1], "replace") == 0)
|
|
/* make a new one */
|
|
{
|
|
/* argv[2] = name */
|
|
/* argv[3] must be type */
|
|
if (argc < 4) {
|
|
SCWrite(pCon, "ERROR: no type specified for Environment Controller",
|
|
eError);
|
|
return 0;
|
|
}
|
|
strtolower(argv[2]);
|
|
strtolower(argv[3]);
|
|
if (FindCommandData(pSics, argv[2], "Environment Controller")) {
|
|
if (strcmp(argv[1], "replace") == 0) {
|
|
if (!RemoveEVController(pCon, argv[2])) {
|
|
return 0;
|
|
}
|
|
} else {
|
|
snprintf(pBueffel, 511,
|
|
"ERROR: environment device %s already installed, delete first",
|
|
argv[2]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
}
|
|
pCom = FindCommand(pSics, argv[2]);
|
|
if (pCom) {
|
|
snprintf(pBueffel,511, "ERROR: command %s already exists", argv[2]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
pNew = InstallCommonControllers(pSics, pCon, argc, argv, &found);
|
|
if (!found) {
|
|
site = getSite();
|
|
if (site != NULL) {
|
|
pNew = site->InstallEnvironmentController(pSics, pCon, argc, argv);
|
|
} else {
|
|
snprintf(pBueffel,511,
|
|
"ERROR: %s not recognized as a valid driver type",
|
|
argv[3]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
pNew = NULL;
|
|
}
|
|
}
|
|
if (pNew == NULL) {
|
|
/* error message is already written */
|
|
return 0;
|
|
}
|
|
if (pNew->pDriv->SavePars) {
|
|
pNew->creationArgs = Arg2Tcl(argc - 3, argv + 3, NULL, 0);
|
|
pNew->pDes->SaveStatus = EVSaveStatus;
|
|
} else {
|
|
pNew->creationArgs = NULL;
|
|
}
|
|
|
|
EVRegisterController(FindEMON(pSics), argv[2], pNew, pCon);
|
|
pNew->driverName = strdup(argv[3]);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
SCWrite(pCon, "ERROR: command not understood", eError);
|
|
return 0;
|
|
}
|