1464 lines
42 KiB
C
1464 lines
42 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 staticstics added.
|
|
Mark Koennecke, July 2006
|
|
|
|
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){
|
|
strcpy(fileBuffer,fileName);
|
|
} 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,
|
|
tv.tv_sec, tv.tv_usec);
|
|
fflush(devLog);
|
|
}
|
|
}
|
|
/*======================== internal data structures =======================*/
|
|
typedef struct _DevEntry {
|
|
void *pData;
|
|
pObjectDescriptor pDescriptor;
|
|
float fVal;
|
|
char *name;
|
|
commandContext comCon;
|
|
} DevEntry, *pDevEntry;
|
|
/*------------------------------------------------------------------------*/
|
|
typedef struct {
|
|
pExeList self;
|
|
pDevEntry pDev;
|
|
pICountable pCountInt;
|
|
pIDrivable pDrivInt;
|
|
}checkContext, *pCheckContext;
|
|
/*-------------------------------------------------------------------------*/
|
|
static pDevEntry CreateDevEntry(pObjectDescriptor pDes, void *pData,
|
|
float fVal, char *name)
|
|
{
|
|
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;
|
|
memset(&pNew->comCon,0,sizeof(commandContext));
|
|
return pNew;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
static void DeleteDevEntry(pDevEntry self)
|
|
{
|
|
assert(self);
|
|
|
|
if(self->name)
|
|
{
|
|
free(self->name);
|
|
}
|
|
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);
|
|
|
|
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);
|
|
}
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
int StartDevice(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)
|
|
{
|
|
if(pCon != self->pOwner)
|
|
{
|
|
/* 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) {
|
|
self->pOwner = pCon;
|
|
} else {
|
|
SCWrite(pCon,
|
|
"ERROR: somebody else is still driving, Request rejected",eError);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self->pOwner = 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,pData,fNew,name);
|
|
if(!pNew)
|
|
{
|
|
SCWrite(pCon,"ERROR: memory exhausted in Device Executor ",eError);
|
|
return 0;
|
|
}
|
|
pNew->comCon = SCGetContext(pCon);
|
|
strncpy(pNew->comCon.deviceID,name,SCDEVIDLEN);
|
|
|
|
/* 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,eWarning);
|
|
}
|
|
}
|
|
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->comCon.deviceID)
|
|
{
|
|
snprintf(pBueffel,130,"started (%s)",pNew->comCon.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
|
|
{
|
|
sprintf(pBueffel,"ERROR: cannot start device %s",name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
DeleteDevEntry(pNew);
|
|
if(LLDcheck(self->iList) >= LIST_EMPTY)
|
|
{
|
|
self->pOwner = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
/*-----------------------------------------------------------------------*/
|
|
/*--------------------------------------------------------------------------*/
|
|
int StartMotor(pExeList self, SicsInterp *pSics, SConnection *pCon,
|
|
char *name, float fVal)
|
|
{
|
|
pDummy pMot = NULL;
|
|
CommandList *pCom = NULL;
|
|
char pBueffel[256];
|
|
|
|
assert(self);
|
|
assert(pSics);
|
|
assert(name);
|
|
|
|
pCom = FindCommand(pSics,name);
|
|
if(!pCom)
|
|
{
|
|
sprintf(pBueffel,"ERROR: cannot find motor %s",name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0;
|
|
}
|
|
pMot = (pDummy)pCom->pData;
|
|
if(!pMot)
|
|
{
|
|
sprintf(pBueffel,"ERROR: %s is no motor ",name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0;
|
|
}
|
|
|
|
|
|
if(!pMot->pDescriptor)
|
|
{
|
|
sprintf(pBueffel,"ERROR: cannot find motor %s",name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0;
|
|
}
|
|
if(!pMot->pDescriptor->GetInterface(pMot,DRIVEID))
|
|
{
|
|
sprintf(pBueffel,"ERROR: %s is no motor",name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0;
|
|
}
|
|
return StartDevice(self,name,pMot->pDescriptor,(void *)pMot,pCon,fVal);
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
int StartCounter(pExeList self, SicsInterp *pSics,SConnection *pCon,
|
|
char *name)
|
|
{
|
|
pCounter pCter = NULL;
|
|
CommandList *pCom = NULL;
|
|
char pBueffel[256];
|
|
|
|
assert(self);
|
|
assert(pSics);
|
|
assert(name);
|
|
|
|
pCom = FindCommand(pSics,name);
|
|
if(!pCom)
|
|
{
|
|
sprintf(pBueffel,"ERROR: cannot find counter %s",name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0;
|
|
}
|
|
pCter = (pCounter)pCom->pData;
|
|
if(!pCter)
|
|
{
|
|
sprintf(pBueffel,"ERROR: %s is no counter ",name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0;
|
|
}
|
|
|
|
|
|
if(!pCter->pDes)
|
|
{
|
|
sprintf(pBueffel,"ERROR: cannot find counter %s",name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0;
|
|
}
|
|
if(!pCter->pDes->GetInterface(pCter,COUNTID))
|
|
{
|
|
sprintf(pBueffel,"ERROR: %s is no counter",name);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0;
|
|
}
|
|
return StartDevice(self,name,pCter->pDes,(void *)pCter,
|
|
pCon,pCter->pDriv->fPreset);
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int CheckExeListOld(pExeList self)
|
|
{
|
|
int iRet;
|
|
pDevEntry pDev = NULL;
|
|
pICountable pCountInt = NULL;
|
|
pIDrivable pDrivInt = NULL;
|
|
int eCode;
|
|
int isCounting=0, isDriving=0;
|
|
char pBueffel[512];
|
|
SConnection *pCon;
|
|
pCon = self->pOwner;
|
|
|
|
assert(self);
|
|
|
|
/* Sometimes this gets called, though nothing is running. There are
|
|
cases where this is feasible for maintainance, but in some cases it
|
|
is pure rubbish, because nothing runs. This will be checked here.
|
|
*/
|
|
if((self->pOwner == NULL) || (LLDcheck(self->iList) == LIST_EMPTY))
|
|
{
|
|
self->iRun = 0;
|
|
self->iEnd = 1;
|
|
self->iStop = 0;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
check the status of all registered devices. Remove when finished
|
|
*/
|
|
iRet = LLDnodePtr2First(self->iList);
|
|
while(iRet != 0)
|
|
{
|
|
LLDnodeDataTo(self->iList,&pDev);
|
|
if(pDev)
|
|
{
|
|
SCPushContext(self->pOwner, pDev->comCon.transID, pDev->comCon.deviceID);
|
|
|
|
pDrivInt = pDev->pDescriptor->GetInterface(pDev->pData,DRIVEID);
|
|
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData,COUNTID);
|
|
|
|
if(pDrivInt)
|
|
{
|
|
eCode = pDrivInt->CheckStatus(pDev->pData,self->pOwner);
|
|
}
|
|
else if(pCountInt)
|
|
{
|
|
eCode = pCountInt->CheckCountStatus(pDev->pData,self->pOwner);
|
|
}
|
|
switch(eCode)
|
|
{
|
|
case HWIdle:
|
|
case OKOK:
|
|
if(pCountInt)
|
|
{
|
|
pCountInt->TransferData(pDev->pData,self->pOwner);
|
|
}
|
|
else if(pDrivInt)
|
|
{
|
|
pDrivInt->iErrorCount = 0;
|
|
}
|
|
ExeInterest(self, pDev, "finished");
|
|
DeleteDevEntry(pDev);
|
|
LLDnodeDelete(self->iList);
|
|
SCWrite(pCon, "", eFinish);
|
|
iRet = LLDnodePtr2Prev(self->iList);
|
|
if(SCGetInterrupt(self->pOwner) != eContinue)
|
|
{
|
|
self->iStatus = DEVINT;
|
|
SCPopContext(self->pOwner);
|
|
return -1;
|
|
}
|
|
self->iStatus = DEVDONE;
|
|
break;
|
|
case HWFault: /* real HW error: burning, no net etc.. */
|
|
ExeInterest(self, pDev, "finished with problem");
|
|
DeleteDevEntry(pDev);
|
|
pDev = NULL;
|
|
SCWrite(pCon, "", eFinish);
|
|
LLDnodeDataTo(self->iList,&pDev);
|
|
LLDnodeDelete(self->iList);
|
|
iRet = LLDnodePtr2Prev(self->iList);
|
|
self->iStatus = DEVERROR;
|
|
if(pDrivInt)
|
|
{
|
|
pDrivInt->iErrorCount++;
|
|
}
|
|
if(SCGetInterrupt(self->pOwner) != eContinue)
|
|
{
|
|
self->iStatus = DEVINT;
|
|
SCPopContext(self->pOwner);
|
|
return -1;
|
|
}
|
|
break;
|
|
case HWNoBeam:
|
|
SetStatus(eOutOfBeam);
|
|
if(SCGetInterrupt(self->pOwner) != eContinue)
|
|
{
|
|
SetStatus(eEager);
|
|
self->iStatus = DEVINT;
|
|
SCPopContext(self->pOwner);
|
|
return -1;
|
|
}
|
|
break;
|
|
case HWPause:
|
|
SetStatus(ePaused);
|
|
if(SCGetInterrupt(self->pOwner) != eContinue)
|
|
{
|
|
ContinueExecution(self);
|
|
self->iStatus = DEVINT;
|
|
SCPopContext(self->pOwner);
|
|
return -1;
|
|
}
|
|
break;
|
|
case HWBusy:
|
|
if(pDrivInt != NULL)
|
|
{
|
|
isDriving = 1;
|
|
}
|
|
else if(pCountInt != NULL)
|
|
{
|
|
isCounting = 1;
|
|
}
|
|
self->iStatus = DEVBUSY;
|
|
break;
|
|
case HWPosFault: /* cannot get somewhere... */
|
|
ExeInterest(self, pDev, "finished with problem");
|
|
DeleteDevEntry(pDev);
|
|
LLDnodeDelete(self->iList);
|
|
SCWrite(pCon, "", eFinish);
|
|
self->iStatus = DEVERROR;
|
|
if(pDrivInt)
|
|
{
|
|
pDrivInt->iErrorCount++;
|
|
}
|
|
if(SCGetInterrupt(self->pOwner) != eContinue)
|
|
{
|
|
self->iStatus = DEVINT;
|
|
SCPopContext(self->pOwner);
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
SCPopContext(self->pOwner);
|
|
}
|
|
iRet = LLDnodePtr2Next(self->iList);
|
|
}
|
|
|
|
if (isCounting) {
|
|
if (isDriving) {
|
|
SetStatus(eCountDrive);
|
|
} else {
|
|
SetStatus(eCounting);
|
|
}
|
|
} else if (isDriving) {
|
|
SetStatus(eDriving);
|
|
}
|
|
|
|
iRet = LLDnodePtr2First(self->iList);
|
|
if(LLDcheck(self->iList) == LIST_EMPTY)
|
|
{
|
|
self->pOwner = NULL;
|
|
self->iEnd = 1;
|
|
self->iRun = 0;
|
|
self->lTask = -1;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
static int checkInterrupt(pCheckContext pCheck, int targetStatus){
|
|
if(SCGetInterrupt(pCheck->self->pOwner) != eContinue) {
|
|
pCheck->self->iStatus = DEVINT;
|
|
SCPopContext(pCheck->self->pOwner);
|
|
SetStatus(eEager);
|
|
return -1;
|
|
} else {
|
|
return targetStatus;
|
|
}
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int initializeCheck(pCheckContext pCheck, pDevEntry pDev){
|
|
int eCode;
|
|
|
|
SCPushContext(pCheck->self->pOwner,
|
|
pDev->comCon.transID, pDev->comCon.deviceID);
|
|
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,pCheck->self->pOwner);
|
|
} else if(pCheck->pCountInt != NULL) {
|
|
eCode = pCheck->pCountInt->CheckCountStatus(pDev->pData,pCheck->self->pOwner);
|
|
}
|
|
return eCode;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int finishDevice(pCheckContext pCheck){
|
|
int status;
|
|
|
|
if(pCheck->pCountInt != NULL) {
|
|
pCheck->pCountInt->TransferData(pCheck->pDev->pData,pCheck->self->pOwner);
|
|
} 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)) {
|
|
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];
|
|
SConnection *pCon;
|
|
pCon = self->pOwner;
|
|
|
|
assert(self);
|
|
|
|
/* Sometimes this gets called, though nothing is running. There are
|
|
cases where this is feasible for maintainance, 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;
|
|
}
|
|
SCPopContext(self->pOwner);
|
|
}
|
|
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);
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
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);
|
|
#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",eStatus);
|
|
return 1;
|
|
}
|
|
else if(iRet == -1)
|
|
{
|
|
SCWrite(pCon,"Handling Interrupt",eStatus);
|
|
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,eStatus);
|
|
}
|
|
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);
|
|
}
|
|
SCPushContext(self->pOwner,0,"system");
|
|
SCWrite(self->pOwner,"ERROR: Full Stop called!!",eError);
|
|
SCPopContext(self->pOwner);
|
|
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 StopExeWait(pExeList self)
|
|
{
|
|
StopExe(self,"all");
|
|
Wait4Success(self);
|
|
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)
|
|
{
|
|
SCPushContext(self->pOwner, pDev->comCon.transID, pDev->comCon.deviceID);
|
|
|
|
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData,COUNTID);
|
|
if(pCountInt)
|
|
{
|
|
iRet = pCountInt->Pause(pDev->pData,self->pOwner);
|
|
if(!iRet)
|
|
{
|
|
iRes = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
SCPopContext(self->pOwner);
|
|
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)
|
|
{
|
|
SCPushContext(self->pOwner, pDev->comCon.transID, pDev->comCon.deviceID);
|
|
iRet = pCountInt->Continue(pDev->pData,self->pOwner);
|
|
if(!iRet)
|
|
{
|
|
iRes = 0;
|
|
}
|
|
SCPopContext(self->pOwner);
|
|
}
|
|
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
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)
|
|
{
|
|
sprintf(pBueffel,"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,
|
|
commandContext cc)
|
|
{
|
|
assert(pCon);
|
|
assert(text);
|
|
|
|
SCPushContext2(pCon,cc);
|
|
SCWrite(pCon, text, eValue);
|
|
SCPopContext(pCon);
|
|
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, SCGetContext(pCon),
|
|
DRIVSTAT, DrivStatCallback,
|
|
pCon, NULL);
|
|
SCRegister(pCon, pSics, self->pCall,list);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
if (strcmp(argv[1], "uninterest") == 0)
|
|
{
|
|
RemoveCallback2(self->pCall, pCon);
|
|
SCUnregister(pCon, self->pCall);
|
|
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
|
|
*/
|
|
|
|
int Success(SConnection *pCon, SicsInterp *pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
int iRet;
|
|
Status eOld;
|
|
|
|
eOld = GetStatus();
|
|
SetStatus(eRunning);
|
|
iRet = Wait4Success((pExeList)pData);
|
|
if(iRet == DEVINT)
|
|
{
|
|
if(SCGetInterrupt(pCon) == eAbortOperation)
|
|
{
|
|
SCSetInterrupt(pCon,eContinue);
|
|
iRet = 0;
|
|
}
|
|
}
|
|
else if(iRet == DEVDONE)
|
|
{
|
|
SCWrite(pCon,"All done",eStatus);
|
|
iRet = 1;
|
|
}
|
|
else if(iRet == DEVERROR)
|
|
{
|
|
SCWrite(pCon,"Finished with Problems",eStatus);
|
|
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];
|
|
|
|
pExeList self = (pExeList)pData;
|
|
if(argc < 2)
|
|
{
|
|
SCWrite(pCon,"ERROR: not enough argumentd 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 {
|
|
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;
|
|
|
|
self = (pExeList)pEL;
|
|
assert(self);
|
|
|
|
if(iSignal == SICSINT)
|
|
{
|
|
iInt = (int *)pSigData;
|
|
if(*iInt != eContinue)
|
|
{
|
|
if(self->pOwner)
|
|
{
|
|
SCPushContext(self->pOwner,0,"system");
|
|
SCWrite(self->pOwner,
|
|
"ERROR: Interrupting Current Hardware Operation",
|
|
eError);
|
|
SCSetInterrupt(self->pOwner,*iInt);
|
|
SCPopContext(self->pOwner);
|
|
}
|
|
StopExe(self,"all");
|
|
}
|
|
}
|
|
}
|
|
/*--------------------------------------------------------------------*/
|
|
void LockDeviceExecutor(pExeList self)
|
|
{
|
|
assert(self);
|
|
self->iLock = 1;
|
|
}
|
|
/*--------------------------------------------------------------------*/
|
|
void UnlockDeviceExecutor(pExeList self)
|
|
{
|
|
assert(self);
|
|
self->iLock = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|