1625 lines
45 KiB
C
1625 lines
45 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"
|
|
#include "commandlog.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) {
|
|
savedStatus = GetStatus();
|
|
SetStatus(eBatch);
|
|
pTcl = InterpGetTcl(pServ->pSics);
|
|
snprintf(pBueffel, sizeof(pBueffel), "%s %f", self->runScript, fVal);
|
|
iRet = Tcl_Eval(pTcl,pBueffel);
|
|
SetStatus(savedStatus);
|
|
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;
|
|
SCSave(&self->conn, pCon);
|
|
|
|
/* 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.)
|
|
{
|
|
sprintf(pBueffel,"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 */
|
|
{
|
|
sprintf(pBueffel,"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;
|
|
}
|
|
if(fDelta <= tol) /* inside tolerance */
|
|
{
|
|
tmo = (int)(ObVal(self->pParam, SETTLE));
|
|
if (self->lastt <= 0) /* lastt negative: -seconds already waited */
|
|
{
|
|
self->lastt += now;
|
|
if (tmo>0)
|
|
{
|
|
sprintf(pBueffel,"%s inside tolerance, wait %.2f sec to settle",
|
|
self->pName, (self->lastt + tmo - now)*1.0);
|
|
SCWrite(pCon,pBueffel,eWarning);
|
|
}
|
|
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 */
|
|
sprintf(pBueffel,"%s outside tolerance, settling time suspended",
|
|
self->pName);
|
|
SCWrite(pCon,pBueffel,eWarning);
|
|
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);
|
|
strncpy(pError,pBueffel,iErrLen);
|
|
return 0;
|
|
}
|
|
|
|
/* upper limit */
|
|
if( fVal > ObVal(self->pParam, UPLIMIT))
|
|
{
|
|
sprintf(pBueffel,"ERROR: %g violates upper limit of device",fVal);
|
|
strncpy(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, SCStore *conn)
|
|
{
|
|
pExeList pExe;
|
|
SConnection *pCon = NULL;
|
|
|
|
pExe = GetExecutor();
|
|
pCon = GetExeOwner(pExe);
|
|
|
|
if (!pCon)
|
|
{
|
|
pCon = SCLoad(conn);
|
|
}
|
|
if(pCon)
|
|
{
|
|
SCWrite(pCon,txt,eWarning);
|
|
}
|
|
else
|
|
{
|
|
ServerWriteGlobal(txt,eWarning);
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------------------*/
|
|
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)
|
|
{
|
|
sprintf(pBueffel,"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",eError);
|
|
PauseExecution(pExe);
|
|
|
|
/* wait till OK */
|
|
iRet = 0;
|
|
while(iRet == 0 && IsCounting(pExe) )
|
|
{
|
|
SicsWait(5);
|
|
iRet = self->pEnvir->IsInTolerance(self);
|
|
}
|
|
|
|
/* OK now, continue */
|
|
SetStatus(eEager);
|
|
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)
|
|
{
|
|
sprintf(pBueffel,"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)
|
|
{
|
|
sprintf(pBueffel,"%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);
|
|
WriteToCommandLog("emon>> ",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;
|
|
|
|
/* 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);
|
|
}
|
|
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, fVal);
|
|
if(!iRet)
|
|
{
|
|
sprintf(pBueffel,"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;
|
|
char pBueffel[512];
|
|
int iRet;
|
|
|
|
assert(self);
|
|
assert(pCon);
|
|
|
|
iRet = ObParSet(self->pParam,self->pName,name,fVal,pCon);
|
|
if(!iRet)
|
|
{
|
|
return iRet;
|
|
}
|
|
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,
|
|
commandContext cc)
|
|
{
|
|
char *pBuf = (char *)pEventData;
|
|
SConnection *pCon = (SConnection *)pUserData;
|
|
char pBueffel[132];
|
|
|
|
if(iEvent == VALUECHANGE)
|
|
{
|
|
pCon->conEventType=POSITION;
|
|
SCWriteInContext(pCon,pBuf,eEvent,cc);
|
|
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);
|
|
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, SCGetContext(pCon),
|
|
VALUECHANGE, EVCallBack,
|
|
pCon, NULL);
|
|
SCRegister(pCon,pSics, self->pCall,lID);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
else if(strcmp(argv[1],"uninterest") == 0)
|
|
{
|
|
RemoveCallback2(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)
|
|
{
|
|
sprintf(pBueffel,"ERROR: parameter %s NOT found",
|
|
argv[1]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
sprintf(pBueffel,"%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)
|
|
{
|
|
sprintf(pBueffel,"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)
|
|
{
|
|
sprintf(pBueffel,"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)
|
|
{
|
|
sprintf(pBueffel,"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 {
|
|
sprintf(pBueffel,
|
|
"ERROR: environment device %s already installed, delete first",
|
|
argv[2]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0;
|
|
}
|
|
}
|
|
pCom = FindCommand(pSics,argv[2]);
|
|
if(pCom)
|
|
{
|
|
sprintf(pBueffel, "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 {
|
|
sprintf(pBueffel,
|
|
"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;
|
|
}
|
|
|
|
|
|
|