1479 lines
39 KiB
C
1479 lines
39 KiB
C
/*-------------------------------------------------------------------------
|
|
|
|
D E V I C E E X E C U T E R
|
|
|
|
|
|
Mark Koennecke, December 1996
|
|
Substantial rewrite: Mark Koennecke, February 1997
|
|
revised: Mark Koennecke, June 1997
|
|
revised for use with tasker: Mark Koennecke, September 1997
|
|
Locking added: Mark Koennecke, August 2002
|
|
|
|
Refactored and instrumentation for instrument statistics added.
|
|
Mark Koennecke, July 2006
|
|
|
|
Reworked to use copied connection objects instead of context pushes.
|
|
Mark Koennecke, January 2009
|
|
|
|
Modified to accommodate run levels
|
|
Mark Koennecke, April 2009
|
|
|
|
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 <stdlib.h>
|
|
#include <assert.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
#include <sys/time.h>
|
|
#include "fortify.h"
|
|
#include "sics.h"
|
|
#include "nserver.h"
|
|
#include "motor.h"
|
|
#include "countdriv.h"
|
|
#include "counter.h"
|
|
#include "devexec.h"
|
|
#include "status.h"
|
|
#include "lld.h"
|
|
#include "commandlog.h"
|
|
#include "ifile.h"
|
|
|
|
/*
|
|
#define DEBUG 1
|
|
*/
|
|
|
|
/*======================== Logging stuff ==================================*/
|
|
static FILE *devLog = NULL;
|
|
/*-------------------------------------------------------------------------*/
|
|
int openDevexecLog()
|
|
{
|
|
char *fileName = NULL;
|
|
char fileBuffer[1024];
|
|
time_t iDate;
|
|
struct tm *psTime;
|
|
|
|
|
|
if (devLog == NULL) {
|
|
fileName = IFindOption(pSICSOptions, "devexeclog");
|
|
if (fileName != NULL) {
|
|
strlcpy(fileBuffer, fileName,1024);
|
|
} else {
|
|
iDate = time(NULL);
|
|
psTime = localtime(&iDate);
|
|
fileBuffer[0] = '\0';
|
|
fileName = getenv("HOME");
|
|
if (fileName != NULL) {
|
|
snprintf(fileBuffer, 1023, "%s/log/devexec%4.4d.log",
|
|
fileName, psTime->tm_year + 1900);
|
|
}
|
|
}
|
|
devLog = fopen(fileBuffer, "a+");
|
|
}
|
|
if (devLog == NULL) {
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
void DevexecLog(char *operation, char *device)
|
|
{
|
|
struct timeval tv;
|
|
struct timezone tm;
|
|
if (devLog != NULL) {
|
|
gettimeofday(&tv, &tm);
|
|
fprintf(devLog, "DEVEXEC:%s:%s:%ld:%ld\n", operation, device,
|
|
(long) tv.tv_sec, (long) tv.tv_usec);
|
|
fflush(devLog);
|
|
}
|
|
traceDevice("devexec","%s:%s",device, operation);
|
|
}
|
|
|
|
/*======================== internal data structures =======================*/
|
|
typedef struct _DevEntry {
|
|
void *pData;
|
|
pObjectDescriptor pDescriptor;
|
|
float fVal;
|
|
char *name;
|
|
SConnection *pCon;
|
|
int level;
|
|
} DevEntry, *pDevEntry;
|
|
/*------------------------------------------------------------------------*/
|
|
typedef struct {
|
|
pExeList self;
|
|
pDevEntry pDev;
|
|
pICountable pCountInt;
|
|
pIDrivable pDrivInt;
|
|
} checkContext, *pCheckContext;
|
|
/*-------------------------------------------------------------------------*/
|
|
static pDevEntry CreateDevEntry(pObjectDescriptor pDes, SConnection * pCon,
|
|
void *pData, float fVal, char *name, int level)
|
|
{
|
|
pDevEntry pNew = NULL;
|
|
|
|
assert(pDes);
|
|
|
|
pNew = (pDevEntry) malloc(sizeof(DevEntry));
|
|
if (!pNew) {
|
|
return NULL;
|
|
}
|
|
pNew->pDescriptor = pDes;
|
|
pNew->pData = pData;
|
|
pNew->name = strdup(name);
|
|
pNew->fVal = fVal;
|
|
pNew->pCon = SCCopyConnection(pCon);
|
|
pNew->pCon->runLevel = level;
|
|
pNew->level = level;
|
|
return pNew;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static void DeleteDevEntry(pDevEntry self)
|
|
{
|
|
assert(self);
|
|
|
|
if (self->name) {
|
|
free(self->name);
|
|
}
|
|
if (self->pCon) {
|
|
SCDeleteConnection(self->pCon);
|
|
}
|
|
free(self);
|
|
}
|
|
|
|
/* ----------------- The Executor himself ---------------------------------*/
|
|
typedef struct __EXELIST {
|
|
pObjectDescriptor pDes;
|
|
SConnection *pOwner;
|
|
int iList;
|
|
int iRun;
|
|
int iStop;
|
|
int iStatus;
|
|
int iEnd;
|
|
int drivePrint;
|
|
long lTask;
|
|
pTaskMan pTask;
|
|
int iLock;
|
|
pICallBack pCall;
|
|
time_t lastRun;
|
|
int paused;
|
|
int taskRunning;
|
|
} ExeList;
|
|
|
|
static pExeList pExecutor = NULL;
|
|
/*--------------------------------------------------------------------------*/
|
|
static void *DevexecInterface(void *pData, int iInter)
|
|
{
|
|
pExeList self = NULL;
|
|
|
|
self = (pExeList) pData;
|
|
assert(self);
|
|
|
|
if (iInter == CALLBACKINTERFACE) {
|
|
return self->pCall;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
pExeList CreateExeList(pTaskMan pTask)
|
|
{
|
|
pExeList pRes = NULL;
|
|
|
|
assert(pTask);
|
|
|
|
pRes = (pExeList) malloc(sizeof(ExeList));
|
|
if (!pRes) {
|
|
return NULL;
|
|
}
|
|
|
|
pRes->pOwner = NULL;
|
|
pRes->pDes = CreateDescriptor("DeviceExecutor");
|
|
if (!pRes->pDes) {
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
pRes->iList = LLDcreate(sizeof(pDevEntry));
|
|
if (pRes->iList == -1) {
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
pRes->iRun = 0;
|
|
pRes->iStatus = DEVDONE;
|
|
pRes->pTask = pTask;
|
|
pRes->lTask = -1;
|
|
pRes->iLock = 0;
|
|
pRes->drivePrint = 0;
|
|
pRes->paused = 0;
|
|
pRes->taskRunning = 0;
|
|
pRes->pCall = CreateCallBackInterface();
|
|
pRes->lastRun = time(NULL);
|
|
pRes->pDes->GetInterface = DevexecInterface;
|
|
return pRes;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
void DeleteExeList(void *pData)
|
|
{
|
|
pExeList self;
|
|
|
|
assert(pData);
|
|
|
|
self = (pExeList) pData;
|
|
if (self->pDes)
|
|
DeleteDescriptor(self->pDes);
|
|
ClearExecutor(self);
|
|
LLDdelete(self->iList);
|
|
if (self->pCall)
|
|
DeleteCallBackInterface(self->pCall);
|
|
|
|
if (self->pOwner) {
|
|
SCDeleteConnection(self->pOwner);
|
|
self->pOwner = NULL;
|
|
}
|
|
|
|
free(self);
|
|
pServ->pExecutor = NULL;
|
|
if (devLog != NULL) {
|
|
fclose(devLog);
|
|
devLog = NULL;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
void ExeInterest(pExeList self, pDevEntry pDev, char *text)
|
|
{
|
|
char buf[128];
|
|
|
|
if (pDev) {
|
|
snprintf(buf, sizeof(buf), "%s %s", pDev->name, text);
|
|
InvokeCallBack(self->pCall, DRIVSTAT, buf);
|
|
}
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
void InvokeNewTarget(pExeList self, char *name, float target)
|
|
{
|
|
NewTarget targetEvent;
|
|
|
|
targetEvent.name = strdup(name);
|
|
targetEvent.target = target;
|
|
InvokeCallBack(self->pCall, NEWTARGET, &targetEvent);
|
|
if(targetEvent.name != NULL){
|
|
free(targetEvent.name);
|
|
}
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
int StartDevice(pExeList self, char *name, pObjectDescriptor pDes,
|
|
void *pData, SConnection * pCon, int level, float fNew)
|
|
{
|
|
pDevEntry pNew = NULL;
|
|
int iRet;
|
|
char pBueffel[132], pError[80];
|
|
pIDrivable pDrivInt = NULL;
|
|
pICountable pCountInt = NULL;
|
|
static int overwriteOwner = -1;
|
|
char *overwriteOption;
|
|
float oldVal;
|
|
|
|
assert(self);
|
|
assert(pDes);
|
|
assert(pCon);
|
|
|
|
/* may we? */
|
|
if (self->pOwner != NULL) {
|
|
if (pCon->ident != self->pOwner->ident) {
|
|
/* this hack helps on rita2, when using the sendsics script
|
|
which opens a client for every command */
|
|
if (overwriteOwner < 0) {
|
|
overwriteOption = IFindOption(pSICSOptions, "overwriteOwner");
|
|
overwriteOwner = overwriteOption && *overwriteOption != '0';
|
|
}
|
|
if (overwriteOwner) {
|
|
SCDeleteConnection(self->pOwner);
|
|
self->pOwner = SCCopyConnection(pCon);
|
|
} else {
|
|
SCWrite(pCon,
|
|
"ERROR: somebody else is still driving, Request rejected",
|
|
eLogError);
|
|
return 0;
|
|
}
|
|
}
|
|
} else {
|
|
self->pOwner = SCCopyConnection(pCon);
|
|
}
|
|
if (self->iLock == 1) {
|
|
SCWrite(pCon, "ERROR: instrument is locked", eError);
|
|
return 0;
|
|
}
|
|
|
|
/* well create a new entry */
|
|
self->iStop = 0;
|
|
pNew = CreateDevEntry(pDes, pCon, pData, fNew, name, level);
|
|
if (!pNew) {
|
|
SCWrite(pCon, "ERROR: memory exhausted in Device Executor ", eError);
|
|
return 0;
|
|
}
|
|
|
|
/* start it */
|
|
pDrivInt = pDes->GetInterface(pData, DRIVEID);
|
|
pCountInt = pDes->GetInterface(pData, COUNTID);
|
|
if (pDrivInt) {
|
|
iRet = pDrivInt->SetValue(pData, pCon, fNew);
|
|
if (iRet == OKOK && self->drivePrint == 1) {
|
|
oldVal = pDrivInt->GetValue(pData, pCon);
|
|
snprintf(pBueffel, 131, "Driving %s from %8.3f to %8.3f",
|
|
name, oldVal, fNew);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
}
|
|
if(iRet == OKOK){
|
|
InvokeNewTarget(self,name,fNew);
|
|
}
|
|
} else if (pCountInt) {
|
|
iRet = pCountInt->StartCount(pData, pCon);
|
|
} else { /* this is a programmers error */
|
|
SCWrite(pCon, "ERROR: Programmer error in StartDevice ", eError);
|
|
iRet = 0;
|
|
}
|
|
|
|
/* check return status */
|
|
if (iRet == OKOK) {
|
|
LLDnodeAppendFrom(self->iList, &pNew);
|
|
sprintf(pBueffel, "started");
|
|
if (NULL != pNew->pCon->deviceID) {
|
|
snprintf(pBueffel, 130, "started (%s)", pNew->pCon->deviceID);
|
|
}
|
|
ExeInterest(self, pNew, pBueffel);
|
|
self->iRun = 1;
|
|
self->iStatus = DEVDONE;
|
|
/* if no task: start it */
|
|
if (self->lTask < 0) {
|
|
self->lTask = TaskRegister(self->pTask,
|
|
DevExecTask,
|
|
DevExecSignal, NULL, self, 1);
|
|
self->iEnd = 0;
|
|
pCon->conStatus = HWBusy;
|
|
}
|
|
DevexecLog("START", pNew->name);
|
|
return 1;
|
|
} else {
|
|
snprintf(pBueffel,131, "ERROR: cannot start device %s", name);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
DeleteDevEntry(pNew);
|
|
if (LLDcheck(self->iList) >= LIST_EMPTY) {
|
|
if (self->pOwner != NULL) {
|
|
SCDeleteConnection(self->pOwner);
|
|
}
|
|
self->pOwner = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
/*------------------------------------------------------------------------
|
|
* This is a hacking thing to bypass the whole access checking thing. I
|
|
* need it at POLDI to run the fucking high voltage while the instrument is
|
|
* still counting.
|
|
*/
|
|
static int ForceStartDevice(pExeList self, char *name, pObjectDescriptor pDes,
|
|
void *pData, SConnection * pCon, float fNew)
|
|
{
|
|
pDevEntry pNew = NULL;
|
|
int iRet;
|
|
char pBueffel[132], pError[80];
|
|
pIDrivable pDrivInt = NULL;
|
|
pICountable pCountInt = NULL;
|
|
static int overwriteOwner = -1;
|
|
char *overwriteOption;
|
|
float oldVal;
|
|
|
|
assert(self);
|
|
assert(pDes);
|
|
assert(pCon);
|
|
|
|
/* may we? */
|
|
if (self->pOwner != NULL) {
|
|
pCon = self->pOwner;
|
|
}
|
|
if (self->iLock == 1) {
|
|
SCWrite(pCon, "ERROR: instrument is locked", eError);
|
|
return 0;
|
|
}
|
|
|
|
/* well create a new entry */
|
|
self->iStop = 0;
|
|
pNew = CreateDevEntry(pDes, SCCopyConnection(pCon),
|
|
pData, fNew, name, RUNRUN);
|
|
if (!pNew) {
|
|
SCWrite(pCon, "ERROR: memory exhausted in Device Executor ", eError);
|
|
return 0;
|
|
}
|
|
|
|
/* start it */
|
|
pDrivInt = pDes->GetInterface(pData, DRIVEID);
|
|
pCountInt = pDes->GetInterface(pData, COUNTID);
|
|
if (pDrivInt) {
|
|
iRet = pDrivInt->SetValue(pData, pCon, fNew);
|
|
if (iRet == OKOK && self->drivePrint == 1) {
|
|
oldVal = pDrivInt->GetValue(pData, pCon);
|
|
snprintf(pBueffel, 131, "Driving %s from %8.3f to %8.3f",
|
|
name, oldVal, fNew);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
}
|
|
if(iRet == OKOK){
|
|
InvokeNewTarget(self,name,fNew);
|
|
}
|
|
} else if (pCountInt) {
|
|
/**
|
|
* Cannot set count parameters here: means of getting hold of the
|
|
* count mode missing here. As this is a POLDI hack where I only need
|
|
* to run a HV, I omit this now. But it will work if a proper
|
|
* preset and mode is set on a counter to start it.
|
|
*/
|
|
iRet = pCountInt->StartCount(pData, pCon);
|
|
} else { /* this is a programmers error */
|
|
SCWrite(pCon, "ERROR: Programmer error in StartDevice ", eError);
|
|
iRet = 0;
|
|
}
|
|
|
|
/* check return status */
|
|
if (iRet == OKOK) {
|
|
LLDnodeAppendFrom(self->iList, &pNew);
|
|
sprintf(pBueffel, "started");
|
|
if (NULL != pNew->pCon->deviceID) {
|
|
snprintf(pBueffel, 130, "started (%s)", pNew->pCon->deviceID);
|
|
}
|
|
ExeInterest(self, pNew, pBueffel);
|
|
self->iRun = 1;
|
|
self->iStatus = DEVDONE;
|
|
/* if no task: start it */
|
|
if (self->lTask < 0) {
|
|
self->lTask = TaskRegister(self->pTask,
|
|
DevExecTask,
|
|
DevExecSignal, NULL, self, 1);
|
|
self->iEnd = 0;
|
|
pCon->conStatus = HWBusy;
|
|
}
|
|
DevexecLog("START", pNew->name);
|
|
return 1;
|
|
} else {
|
|
snprintf(pBueffel,131, "ERROR: cannot start device %s", name);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
DeleteDevEntry(pNew);
|
|
if (LLDcheck(self->iList) >= LIST_EMPTY) {
|
|
if (self->pOwner != NULL) {
|
|
SCDeleteConnection(self->pOwner);
|
|
}
|
|
self->pOwner = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int StartMotor(pExeList self, SicsInterp * pSics, SConnection * pCon,
|
|
char *name, int level, float fVal)
|
|
{
|
|
pDummy pMot = NULL;
|
|
CommandList *pCom = NULL;
|
|
char pBueffel[256];
|
|
|
|
assert(self);
|
|
assert(pSics);
|
|
assert(name);
|
|
|
|
pCom = FindCommand(pSics, name);
|
|
if (!pCom) {
|
|
snprintf(pBueffel,255, "ERROR: cannot find motor %s", name);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
pMot = (pDummy) pCom->pData;
|
|
if (!pMot) {
|
|
snprintf(pBueffel,255, "ERROR: %s is no motor ", name);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
|
|
|
|
if (!pMot->pDescriptor) {
|
|
snprintf(pBueffel,255, "ERROR: cannot find motor %s", name);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
if (!pMot->pDescriptor->GetInterface(pMot, DRIVEID)) {
|
|
snprintf(pBueffel, 255, "ERROR: %s is no motor", name);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
return StartDevice(self, name, pMot->pDescriptor, (void *) pMot, pCon,
|
|
level, fVal);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int StartCounter(pExeList self, SicsInterp * pSics, SConnection * pCon,
|
|
int level, char *name)
|
|
{
|
|
pCounter pCter = NULL;
|
|
CommandList *pCom = NULL;
|
|
char pBueffel[256];
|
|
|
|
assert(self);
|
|
assert(pSics);
|
|
assert(name);
|
|
|
|
pCom = FindCommand(pSics, name);
|
|
if (!pCom) {
|
|
snprintf(pBueffel,255, "ERROR: cannot find counter %s", name);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
pCter = (pCounter) pCom->pData;
|
|
if (!pCter) {
|
|
snprintf(pBueffel,255, "ERROR: %s is no counter ", name);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
|
|
|
|
if (!pCter->pDes) {
|
|
snprintf(pBueffel, 255, "ERROR: cannot find counter %s", name);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
if (!pCter->pDes->GetInterface(pCter, COUNTID)) {
|
|
snprintf(pBueffel,255, "ERROR: %s is no counter", name);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
return StartDevice(self, name, pCter->pDes, (void *) pCter,
|
|
pCon, level, pCter->pDriv->fPreset);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int checkInterrupt(pCheckContext pCheck, int targetStatus)
|
|
{
|
|
if (SCGetInterrupt(pCheck->self->pOwner) != eContinue) {
|
|
pCheck->self->iStatus = DEVINT;
|
|
SetStatus(eEager);
|
|
return -1;
|
|
} else {
|
|
return targetStatus;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int initializeCheck(pCheckContext pCheck, pDevEntry pDev)
|
|
{
|
|
int eCode = HWFault;
|
|
|
|
pCheck->pDev = pDev;
|
|
pCheck->pDrivInt = pDev->pDescriptor->GetInterface(pDev->pData, DRIVEID);
|
|
pCheck->pCountInt =
|
|
pDev->pDescriptor->GetInterface(pDev->pData, COUNTID);
|
|
if (pCheck->pDrivInt != NULL) {
|
|
eCode = pCheck->pDrivInt->CheckStatus(pDev->pData, pDev->pCon);
|
|
} else if (pCheck->pCountInt != NULL) {
|
|
eCode = pCheck->pCountInt->CheckCountStatus(pDev->pData, pDev->pCon);
|
|
}
|
|
return eCode;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static int finishDevice(pCheckContext pCheck)
|
|
{
|
|
int status;
|
|
|
|
if (pCheck->pCountInt != NULL) {
|
|
pCheck->pCountInt->TransferData(pCheck->pDev->pData,
|
|
pCheck->pDev->pCon);
|
|
} else if (pCheck->pDrivInt != NULL) {
|
|
pCheck->pDrivInt->iErrorCount = 0;
|
|
}
|
|
ExeInterest(pCheck->self, pCheck->pDev, "finished");
|
|
DevexecLog("STOP", pCheck->pDev->name);
|
|
DeleteDevEntry(pCheck->pDev);
|
|
LLDnodeDelete(pCheck->self->iList);
|
|
status = LLDnodePtr2Prev(pCheck->self->iList);
|
|
SCWrite(pCheck->self->pOwner, "", eFinish);
|
|
pCheck->self->iStatus = DEVDONE;
|
|
return checkInterrupt(pCheck, status);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int errorDevice(pCheckContext pCheck)
|
|
{
|
|
int status;
|
|
|
|
ExeInterest(pCheck->self, pCheck->pDev, "finished with problem");
|
|
DevexecLog("STOP", pCheck->pDev->name);
|
|
LLDnodeDelete(pCheck->self->iList);
|
|
status = LLDnodePtr2Prev(pCheck->self->iList);
|
|
SCWrite(pCheck->self->pOwner, "", eFinish);
|
|
pCheck->self->iStatus = DEVERROR;
|
|
if (pCheck->pDrivInt != NULL) {
|
|
pCheck->pDrivInt->iErrorCount++;
|
|
}
|
|
status = checkInterrupt(pCheck, status);
|
|
DeleteDevEntry(pCheck->pDev);
|
|
return status;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int testFinish(pExeList self)
|
|
{
|
|
if ((self->pOwner == NULL) || (LLDcheck(self->iList) == LIST_EMPTY)) {
|
|
if (self->pOwner != NULL) {
|
|
SCDeleteConnection(self->pOwner);
|
|
}
|
|
self->pOwner = NULL;
|
|
self->iRun = 0;
|
|
self->iEnd = 1;
|
|
self->iStop = 0;
|
|
self->lTask = -1;
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int CheckExeList(pExeList self)
|
|
{
|
|
int iRet, status;
|
|
checkContext check;
|
|
pDevEntry pDev = NULL;
|
|
pICountable pCountInt = NULL;
|
|
pIDrivable pDrivInt = NULL;
|
|
int eCode;
|
|
int isCounting = 0, isDriving = 0;
|
|
char pBueffel[512];
|
|
|
|
assert(self);
|
|
|
|
/* Sometimes this gets called, though nothing is running. There are
|
|
cases where this is feasible for maintenance, but in some cases it
|
|
is pure rubbish, because nothing runs. This will be checked here.
|
|
*/
|
|
if (testFinish(self) == 1) {
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
check the status of all registered devices. Remove when finished
|
|
*/
|
|
check.self = self;
|
|
status = LLDnodePtr2First(self->iList);
|
|
while (status != 0) {
|
|
LLDnodeDataTo(self->iList, &pDev);
|
|
if (pDev) {
|
|
eCode = initializeCheck(&check, pDev);
|
|
if (eCode != HWNoBeam && eCode != HWPause && self->paused == 1) {
|
|
DevexecLog("CONTINUE", "ALL");
|
|
self->paused = 0;
|
|
}
|
|
switch (eCode) {
|
|
case HWIdle:
|
|
case OKOK:
|
|
status = finishDevice(&check);
|
|
if (status < 0) {
|
|
return status;
|
|
}
|
|
break;
|
|
case HWFault: /* real HW error: burning, no net etc.. */
|
|
status = errorDevice(&check);
|
|
if (status < 0) {
|
|
return status;
|
|
}
|
|
break;
|
|
case HWNoBeam:
|
|
SetStatus(eOutOfBeam);
|
|
if (self->paused == 0) {
|
|
self->paused = 1;
|
|
DevexecLog("NOBEAM", "ALL");
|
|
}
|
|
status = checkInterrupt(&check, 1);
|
|
if (status < 0) {
|
|
return status;
|
|
}
|
|
break;
|
|
case HWPause:
|
|
SetStatus(ePaused);
|
|
if (self->paused == 0) {
|
|
self->paused = 1;
|
|
DevexecLog("PAUSE", "ALL");
|
|
}
|
|
status = checkInterrupt(&check, 1);
|
|
if (status < 0) {
|
|
/*
|
|
* continue in order to wait for devices to come to a stop
|
|
*/
|
|
ContinueExecution(self);
|
|
return status;
|
|
}
|
|
break;
|
|
case HWBusy:
|
|
if (check.pDrivInt != NULL) {
|
|
isDriving = 1;
|
|
} else if (check.pCountInt != NULL) {
|
|
isCounting = 1;
|
|
}
|
|
self->iStatus = DEVBUSY;
|
|
break;
|
|
case HWPosFault: /* cannot get somewhere... */
|
|
status = errorDevice(&check);
|
|
if (status < 0) {
|
|
return status;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
status = LLDnodePtr2Next(self->iList);
|
|
}
|
|
|
|
if (isCounting) {
|
|
if (isDriving) {
|
|
SetStatus(eCountDrive);
|
|
} else {
|
|
SetStatus(eCounting);
|
|
}
|
|
} else if (isDriving) {
|
|
SetStatus(eDriving);
|
|
}
|
|
|
|
iRet = LLDnodePtr2First(self->iList);
|
|
return testFinish(self);
|
|
}
|
|
/*--------------------------------------------------------------------------
|
|
Cludge to not move the current pointer for CheckExeList
|
|
*/
|
|
void *LLDgetCurrent(int List);
|
|
void LLDsetCurrent(int List, void *pointer);
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int DevExecLevelRunning(pExeList self, int level)
|
|
{
|
|
int iRet;
|
|
pDevEntry pDev = NULL;
|
|
void *current;
|
|
|
|
if(self->lTask < 0){
|
|
return 0;
|
|
}
|
|
current = LLDgetCurrent(self->iList);
|
|
iRet = LLDnodePtr2First(self->iList);
|
|
while (iRet != 0) {
|
|
LLDnodeDataTo(self->iList, &pDev);
|
|
if (pDev) {
|
|
if(pDev->level >= level){
|
|
LLDsetCurrent(self->iList,current);
|
|
return 1;
|
|
}
|
|
}
|
|
iRet = LLDnodePtr2Next(self->iList);
|
|
}
|
|
LLDsetCurrent(self->iList,current);
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int Wait4Success(pExeList self)
|
|
{
|
|
int iRet;
|
|
assert(self);
|
|
|
|
/* do nothing if not running */
|
|
if (self->lTask < 0) {
|
|
printf("Nothing to wait for.... \n");
|
|
self->iRun = 0; /* not sure if this is needed here, but does not harm */
|
|
return self->iStatus;
|
|
}
|
|
|
|
/* wait for Devexec task to finish */
|
|
/*TaskWait(self->pTask, self->lTask); */
|
|
while(DevExecLevelRunning(self,RUNDRIVE)){
|
|
TaskYield(self->pTask);
|
|
}
|
|
#ifdef DEBUG
|
|
printf("Wait4Success finished\n");
|
|
#endif
|
|
self->iRun = 0;
|
|
return self->iStatus;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int ListPending(pExeList self, SConnection * pCon)
|
|
{
|
|
int iRet, i;
|
|
char pBueffel[512];
|
|
pDevEntry pDev = NULL;
|
|
|
|
assert(self);
|
|
assert(pCon);
|
|
|
|
/* first make sure that the list is fully updated */
|
|
iRet = CheckExeList(self);
|
|
if (iRet == 1) { /* nothing to do! */
|
|
SCWrite(pCon, "Machine idle", eValue);
|
|
return 1;
|
|
} else if (iRet == -1) {
|
|
SCWrite(pCon, "Handling Interrupt", eError);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* search the list for entries */
|
|
iRet = LLDnodePtr2First(self->iList);
|
|
while (iRet != 0) {
|
|
LLDnodeDataTo(self->iList, &pDev);
|
|
if (pDev) {
|
|
sprintf(pBueffel, "\t%s %f", pDev->name, pDev->fVal);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
}
|
|
iRet = LLDnodePtr2Next(self->iList);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------*/
|
|
long GetDevexecID(pExeList self)
|
|
{
|
|
assert(self);
|
|
|
|
return self->lTask;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int StopExe(pExeList self, char *name)
|
|
{
|
|
int i, iRet;
|
|
pDevEntry pDev = NULL;
|
|
pIDrivable pDrivInt = NULL;
|
|
pICountable pCountInt = NULL;
|
|
assert(self);
|
|
|
|
/* if not active, nothing to do */
|
|
if ((self->pOwner == NULL) || (LLDcheck(self->iList) == LIST_EMPTY)) {
|
|
self->iRun = 0;
|
|
return 1;
|
|
}
|
|
|
|
/* first the ALL case */
|
|
if (strcmp(name, "all") == 0) {
|
|
/*
|
|
check for stop flag. This is to stop unnecessary calls to StopExe.
|
|
There may be way to many, but each call is reasonable under certain
|
|
circumstances.
|
|
*/
|
|
if (self->iStop == 1) {
|
|
return 0;
|
|
} else {
|
|
self->iStop = 1;
|
|
}
|
|
|
|
iRet = LLDnodePtr2First(self->iList);
|
|
while (iRet != 0) {
|
|
pDev = (pDevEntry) LLDnodePtr(self->iList);
|
|
if (pDev) {
|
|
pDrivInt = pDev->pDescriptor->GetInterface(pDev->pData, DRIVEID);
|
|
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData, COUNTID);
|
|
if (pDrivInt) {
|
|
pDrivInt->Halt(pDev->pData);
|
|
} else if (pCountInt) {
|
|
pCountInt->Halt(pDev->pData);
|
|
}
|
|
}
|
|
iRet = LLDnodePtr2Next(self->iList);
|
|
}
|
|
SCWrite(self->pOwner, "ERROR: Full Stop called!!", eLogError);
|
|
if (SCGetInterrupt(self->pOwner) > eContinue) {
|
|
self->iStatus = DEVINT;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* now the special case: a well defined command */
|
|
iRet = LLDnodePtr2First(self->iList);
|
|
while (iRet != 0) {
|
|
pDev = (pDevEntry) LLDnodePtr(self->iList);
|
|
if (pDev) {
|
|
if (strcmp(pDev->name, name) == 0) {
|
|
pDrivInt = pDev->pDescriptor->GetInterface(pDev->pData, DRIVEID);
|
|
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData, COUNTID);
|
|
if (pDrivInt) {
|
|
pDrivInt->Halt(pDev->pData);
|
|
} else if (pCountInt) {
|
|
pCountInt->Halt(pDev->pData);
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
iRet = LLDnodePtr2Next(self->iList);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int StopByData(pExeList self, void *data)
|
|
{
|
|
int iRet;
|
|
pDevEntry pDev = NULL;
|
|
pIDrivable pDrivInt = NULL;
|
|
pICountable pCountInt = NULL;
|
|
|
|
iRet = LLDnodePtr2First(self->iList);
|
|
while (iRet != 0) {
|
|
pDev = (pDevEntry) LLDnodePtr(self->iList);
|
|
if (pDev) {
|
|
if (pDev->pData == data) {
|
|
pDrivInt = pDev->pDescriptor->GetInterface(pDev->pData, DRIVEID);
|
|
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData, COUNTID);
|
|
if (pDrivInt) {
|
|
pDrivInt->Halt(pDev->pData);
|
|
} else if (pCountInt) {
|
|
pCountInt->Halt(pDev->pData);
|
|
}
|
|
ExeInterest(self, pDev, "finished");
|
|
DevexecLog("FINISHED", pDev->name);
|
|
DeleteDevEntry(pDev);
|
|
LLDnodeDelete(self->iList);
|
|
self->iStatus = DEVDONE;
|
|
SCWrite(self->pOwner, "", eFinish);
|
|
return 1;
|
|
}
|
|
}
|
|
iRet = LLDnodePtr2Next(self->iList);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int StopExeWait(pExeList self)
|
|
{
|
|
StopExe(self, "all");
|
|
while(DevExecLevelRunning(self,RUNRUN)){
|
|
TaskYield(self->pTask);
|
|
}
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int PauseExecution(pExeList self)
|
|
{
|
|
int i, iRet, iRes;
|
|
pDevEntry pDev = NULL;
|
|
pICountable pCountInt = NULL;
|
|
assert(self);
|
|
|
|
/* step through the list */
|
|
iRes = 1;
|
|
iRet = LLDnodePtr2First(self->iList);
|
|
while (iRet != 0) {
|
|
pDev = (pDevEntry) LLDnodePtr(self->iList);
|
|
if (pDev) {
|
|
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData, COUNTID);
|
|
if (pCountInt) {
|
|
iRet = pCountInt->Pause(pDev->pData, pDev->pCon);
|
|
if (!iRet) {
|
|
iRes = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
iRet = LLDnodePtr2Next(self->iList);
|
|
}
|
|
SetStatus(ePaused);
|
|
return iRes;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
int IsCounting(pExeList self)
|
|
{
|
|
int iRet;
|
|
pDevEntry pDev = NULL;
|
|
pICountable pCountInt = NULL;
|
|
assert(self);
|
|
|
|
/* step through the list */
|
|
iRet = LLDnodePtr2First(self->iList);
|
|
while (iRet != 0) {
|
|
pDev = (pDevEntry) LLDnodePtr(self->iList);
|
|
if (pDev) {
|
|
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData, COUNTID);
|
|
if (pCountInt) {
|
|
return 1;
|
|
}
|
|
}
|
|
iRet = LLDnodePtr2Next(self->iList);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int ContinueExecution(pExeList self)
|
|
{
|
|
int i, iRet, iRes;
|
|
pDevEntry pDev = NULL;
|
|
pICountable pCountInt = NULL;
|
|
assert(self);
|
|
|
|
/* step through the list */
|
|
iRes = 1;
|
|
iRet = LLDnodePtr2First(self->iList);
|
|
while (iRet != 0) {
|
|
pDev = (pDevEntry) LLDnodePtr(self->iList);
|
|
if (pDev) {
|
|
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData, COUNTID);
|
|
if (pCountInt) {
|
|
iRet = pCountInt->Continue(pDev->pData, pDev->pCon);
|
|
if (!iRet) {
|
|
iRes = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
iRet = LLDnodePtr2Next(self->iList);
|
|
}
|
|
SetStatus(eCounting);
|
|
return iRes;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
void ClearExecutor(pExeList self)
|
|
{
|
|
int iRet;
|
|
pDevEntry pDev = NULL;
|
|
|
|
assert(self);
|
|
|
|
iRet = LLDnodePtr2First(self->iList);
|
|
while (iRet != 0) {
|
|
pDev = (pDevEntry) LLDnodePtr(self->iList);
|
|
if (pDev) {
|
|
DeleteDevEntry(pDev);
|
|
}
|
|
LLDnodeDelete(self->iList);
|
|
iRet = LLDnodePtr2Prev(self->iList);
|
|
iRet = LLDnodePtr2Next(self->iList);
|
|
}
|
|
if (self->pOwner) {
|
|
if (SCGetInterrupt(self->pOwner) > eContinue) {
|
|
self->iStatus = DEVINT;
|
|
}
|
|
SCDeleteConnection(self->pOwner);
|
|
}
|
|
self->pOwner = NULL;
|
|
self->iEnd = 1;
|
|
self->lTask = -1;
|
|
self->iRun = 0;
|
|
self->iLock = 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int StopCommand(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pExeList self = NULL;
|
|
int iRet;
|
|
char pBueffel[132];
|
|
|
|
assert(pCon);
|
|
assert(pSics);
|
|
assert(pData);
|
|
|
|
/* check Privilege: Muggers may do it */
|
|
if (!SCMatchRights(pCon, usUser)) {
|
|
SCWrite(pCon, "ERROR: NO Privilege to Stop operation ", eError);
|
|
return 0;
|
|
}
|
|
|
|
argtolower(argc, argv);
|
|
self = (pExeList) pData;
|
|
if (argc < 2) {
|
|
ListPending(self, pCon);
|
|
return 1;
|
|
}
|
|
|
|
iRet = StopExe(self, argv[1]);
|
|
if (!iRet) {
|
|
snprintf(pBueffel,131, "ERROR: %s not found, so could not halt", argv[1]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
}
|
|
return iRet;
|
|
}
|
|
|
|
/*------------------- The CallBack function for interest ------------------*/
|
|
static int DrivStatCallback(int iEvent, void *text, void *pCon)
|
|
{
|
|
assert(pCon);
|
|
assert(text);
|
|
SConnection *con = (SConnection *) pCon;
|
|
|
|
if (con == NULL || !SCisConnected(con)) {
|
|
return -1;
|
|
}
|
|
SCWrite(pCon, text, eLog);
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int ListExe(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pExeList self = NULL;
|
|
int list;
|
|
|
|
if (argc == 1) {
|
|
return ListPending((pExeList) pData, pCon);
|
|
}
|
|
argtolower(argc, argv);
|
|
self = (pExeList) pData;
|
|
assert(self);
|
|
if (argc == 2) {
|
|
if (strcmp(argv[1], "interest") == 0) {
|
|
list = RegisterCallback(self->pCall,
|
|
DRIVSTAT, DrivStatCallback,
|
|
SCCopyConnection(pCon), NULL);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
if (strcmp(argv[1], "uninterest") == 0) {
|
|
RemoveCallbackCon(self->pCall, pCon);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
}
|
|
SCWrite(pCon, "ERROR: illegal arguments for ListExe", eError);
|
|
return 0;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int SicsIdle(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pExeList self = NULL;
|
|
int idle;
|
|
char pBueffel[80];
|
|
|
|
self = (pExeList) pData;
|
|
assert(self);
|
|
idle = time(NULL) - self->lastRun;
|
|
snprintf(pBueffel, 79, "sicsidle = %d", idle);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
Usage:
|
|
Success [level]
|
|
*/
|
|
int Success(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
int iRet, level;
|
|
Status eOld;
|
|
pExeList self = (pExeList)pData;
|
|
|
|
eOld = GetStatus();
|
|
SetStatus(eRunning);
|
|
|
|
if(argc > 1){
|
|
if(strcmp(argv[1],"RUNDRIVE") == 0){
|
|
level = RUNDRIVE;
|
|
}
|
|
} else {
|
|
level = RUNRUN;
|
|
}
|
|
|
|
while(DevExecLevelRunning(self, level)){
|
|
TaskYield(self->pTask);
|
|
}
|
|
iRet = self->iStatus;
|
|
if (iRet == DEVINT) {
|
|
if (SCGetInterrupt(pCon) == eAbortOperation) {
|
|
SCSetInterrupt(pCon, eContinue);
|
|
iRet = 1;
|
|
} else {
|
|
iRet = 0;
|
|
}
|
|
} else if (iRet == DEVDONE) {
|
|
SCWrite(pCon, "All done", eValue);
|
|
iRet = 1;
|
|
} else if (iRet == DEVERROR) {
|
|
SCWrite(pCon, "Finished with Problems", eValue);
|
|
iRet = 1;
|
|
}
|
|
SetStatus(eEager);
|
|
return iRet;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int PauseAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
int status;
|
|
|
|
status = PauseExecution((pExeList) pData);
|
|
if (status) {
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else {
|
|
SCWrite(pCon, "ERROR: failed to pause", eError);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
int DevexecAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
int val;
|
|
char pBueffel[256];
|
|
void *data = NULL;
|
|
pDummy pDum = NULL;
|
|
float fTarget;
|
|
CommandList *pCom = NULL;
|
|
|
|
pExeList self = (pExeList) pData;
|
|
if (argc < 2) {
|
|
SCWrite(pCon, "ERROR: not enough arguments to devexec command",
|
|
eError);
|
|
return 0;
|
|
}
|
|
strtolower(argv[1]);
|
|
if (strcmp(argv[1], "driveprint") == 0) {
|
|
if (argc > 2 && SCMatchRights(pCon, usUser)) {
|
|
val = atoi(argv[2]);
|
|
self->drivePrint = val;
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else {
|
|
snprintf(pBueffel, 255, "devexe.drivePrint = %d", self->drivePrint);
|
|
SCWrite(pCon, pBueffel, eValue);
|
|
return 1;
|
|
}
|
|
} else if(strcmp(argv[1],"force") == 0) {
|
|
if(argc < 4){
|
|
SCWrite(pCon,"ERROR: insufficient number of arguments to devexec force",
|
|
eError);
|
|
return 0;
|
|
}
|
|
pCom = FindCommand(pSics,argv[2]);
|
|
fTarget = atof(argv[3]);
|
|
if(pCom == NULL){
|
|
SCPrintf(pCon,eError,"ERROR: command %s to force not found", argv[2]);
|
|
return 0;
|
|
}
|
|
data = pCom->pData;
|
|
pDum = (pDummy)data;
|
|
if(GetDrivableInterface(data) == NULL && GetCountableInterface(data) == NULL ){
|
|
SCPrintf(pCon,eError,"ERROR: command %s not startable", argv[2]);
|
|
return 0;
|
|
}
|
|
val = ForceStartDevice(self,argv[2],pDum->pDescriptor,data, pCon, fTarget);
|
|
return val;
|
|
} else {
|
|
SCWrite(pCon, "ERROR: unknown subcommand to devexec", eError);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int ContinueAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
int status;
|
|
Status eStat;
|
|
|
|
eStat = GetStatus();
|
|
if (eStat != ePaused) {
|
|
SCWrite(pCon, "ERROR: Not paused, ignored", eError);
|
|
return 0;
|
|
}
|
|
|
|
status = ContinueExecution((pExeList) pData);
|
|
if (status) {
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else {
|
|
SCWrite(pCon, "ERROR: failed to pause", eError);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int isInRunMode(pExeList self)
|
|
{
|
|
if (self == NULL) {
|
|
return 0;
|
|
} else {
|
|
return self->iRun;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
SConnection *GetExeOwner(pExeList self)
|
|
{
|
|
if (self == NULL)
|
|
return NULL;
|
|
|
|
return self->pOwner;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int DevExecTask(void *pData)
|
|
{
|
|
pExeList self = NULL;
|
|
char pBueffel[132], pInterrupt[80];
|
|
int iRet, iInterrupt;
|
|
|
|
self = (pExeList) pData;
|
|
|
|
/* am I bound to end ? */
|
|
if (self->iEnd) {
|
|
self->lTask = -1;
|
|
SetStatus(eEager);
|
|
return 0;
|
|
}
|
|
|
|
if (self->taskRunning == 1) {
|
|
printf("DevexecTask reentrant protection triggered\n");
|
|
return 1;
|
|
}
|
|
/*
|
|
* CheckExeList may cause waits and thus reentrant calls to
|
|
* this. Which can cause trouble
|
|
*/
|
|
self->taskRunning = 1;
|
|
iRet = CheckExeList(self);
|
|
self->taskRunning = 0;
|
|
|
|
|
|
self->lastRun = time(NULL);
|
|
switch (iRet) {
|
|
case -1: /* some problem */
|
|
iInterrupt = SCGetInterrupt(self->pOwner);
|
|
if (iInterrupt != eContinue) {
|
|
if (iInterrupt > 1) {
|
|
self->taskRunning = 1;
|
|
StopExe(self, "all");
|
|
self->taskRunning = 0;
|
|
}
|
|
#ifdef DEBUG
|
|
printf("DevExecTask found an error\n");
|
|
#endif
|
|
return 1;
|
|
} else {
|
|
return 1;
|
|
}
|
|
break;
|
|
case 1: /* Success */
|
|
self->lTask = -1;
|
|
self->iEnd = 1;
|
|
SetStatus(eEager);
|
|
#ifdef DEBUG
|
|
printf("DevExecTask finishes on success\n");
|
|
#endif
|
|
return 0;
|
|
break;
|
|
default: /* continue, still busy */
|
|
return 1;
|
|
}
|
|
/* should not get here */
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
void DevExecSignal(void *pEL, int iSignal, void *pSigData)
|
|
{
|
|
int *iInt;
|
|
pExeList self = NULL;
|
|
SConnection *pCon = NULL;
|
|
|
|
self = (pExeList) pEL;
|
|
assert(self);
|
|
|
|
if (iSignal == SICSINT) {
|
|
iInt = (int *) pSigData;
|
|
if (*iInt != eContinue) {
|
|
if (self->pOwner) {
|
|
pCon = SCCopyConnection(self->pOwner);
|
|
if (pCon != NULL) {
|
|
pCon->transID = 0;
|
|
strcpy(pCon->deviceID, "system");
|
|
SCWrite(pCon,
|
|
"ERROR: Interrupting Current Hardware Operation",
|
|
eError);
|
|
SCSetInterrupt(pCon, *iInt);
|
|
SCSetInterrupt(self->pOwner, *iInt);
|
|
SCDeleteConnection(pCon);
|
|
}
|
|
}
|
|
StopExe(self, "all");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
void LockDeviceExecutor(pExeList self)
|
|
{
|
|
assert(self);
|
|
self->iLock = 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
void UnlockDeviceExecutor(pExeList self)
|
|
{
|
|
assert(self);
|
|
self->iLock = 0;
|
|
}
|
|
/*--------------------------------------------------------------------*/
|
|
void DevExecInit(void)
|
|
{
|
|
pExeList pExe = pServ->pExecutor;
|
|
|
|
/* commands to do with the executor. Only StopExe carries the
|
|
DeleteFunction in order to avoid double deletion. All the
|
|
other commands operate on the same datastructure.
|
|
*/
|
|
AddCommand(pServ->pSics, "StopExe", StopCommand, DeleteExeList, pExe);
|
|
AddCommand(pServ->pSics, "ListExe", ListExe, NULL, pExe);
|
|
AddCommand(pServ->pSics, "sicsidle", SicsIdle, NULL, pExe);
|
|
AddCommand(pServ->pSics, "Success", Success, NULL, pExe);
|
|
AddCommand(pServ->pSics, "pause", PauseAction, NULL, pExe);
|
|
AddCommand(pServ->pSics, "continue", ContinueAction, NULL, pExe);
|
|
AddCommand(pServ->pSics, "devexec", DevexecAction, NULL, pExe);
|
|
}
|
|
/*---------------------------------------------------------------------*/
|
|
void *GetExecutorCallback(pExeList self)
|
|
{
|
|
return self->pCall;
|
|
}
|