- Added Pause and Continue commands - Fixed simulation counter to deal properly with pause - Fixed nxdict HDF5 problem SKIPPED: psi/makefile_alpha psi/nextrics.c psi/nxsans.c
1005 lines
27 KiB
C
1005 lines
27 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
|
|
|
|
Copyright:
|
|
|
|
Labor fuer Neutronenstreuung
|
|
Paul Scherrer Institut
|
|
CH-5423 Villigen-PSI
|
|
|
|
|
|
The authors hereby grant permission to use, copy, modify, distribute,
|
|
and license this software and its documentation for any purpose, provided
|
|
that existing copyright notices are retained in all copies and that this
|
|
notice is included verbatim in any distributions. No written agreement,
|
|
license, or royalty fee is required for any of the authorized uses.
|
|
Modifications to this software may be copyrighted by their authors
|
|
and need not follow the licensing terms described here, provided that
|
|
the new terms are clearly indicated on the first page of each file where
|
|
they apply.
|
|
|
|
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
|
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
|
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
|
MODIFICATIONS.
|
|
-----------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include "fortify.h"
|
|
#include "sics.h"
|
|
#include "nserver.h"
|
|
#include "motor.h"
|
|
#include "countdriv.h"
|
|
#include "counter.h"
|
|
#include "devexec.h"
|
|
#include "status.h"
|
|
#include "lld.h"
|
|
|
|
/*
|
|
#define DEBUG 1
|
|
*/
|
|
|
|
typedef struct _DevEntry {
|
|
void *pData;
|
|
pObjectDescriptor pDescriptor;
|
|
float fVal;
|
|
char *name;
|
|
} DevEntry, *pDevEntry;
|
|
/*-------------------------------------------------------------------------*/
|
|
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;
|
|
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;
|
|
long lTask;
|
|
pTaskMan pTask;
|
|
int iLock;
|
|
} ExeList;
|
|
|
|
static pExeList pExecutor = 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;
|
|
return pRes;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
void DeleteExeList(void *pData)
|
|
{
|
|
pExeList self;
|
|
|
|
assert(pData);
|
|
|
|
self = (pExeList)pData;
|
|
if(self->pDes)
|
|
DeleteDescriptor(self->pDes);
|
|
ClearExecutor(self);
|
|
LLDdelete(self->iList);
|
|
|
|
free(self);
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
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;
|
|
|
|
assert(self);
|
|
assert(pDes);
|
|
assert(pCon);
|
|
|
|
/* may we? */
|
|
if(self->pOwner != NULL)
|
|
{
|
|
if(pCon != self->pOwner)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/* start it */
|
|
pDrivInt = pDes->GetInterface(pData,DRIVEID);
|
|
pCountInt = pDes->GetInterface(pData,COUNTID);
|
|
if(pDrivInt)
|
|
{
|
|
iRet = pDrivInt->SetValue(pData,pCon,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);
|
|
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;
|
|
}
|
|
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 CheckExeList(pExeList self)
|
|
{
|
|
int iRet;
|
|
pDevEntry pDev = NULL;
|
|
pICountable pCountInt = NULL;
|
|
pIDrivable pDrivInt = NULL;
|
|
int eCode;
|
|
|
|
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 ne checkd 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)
|
|
{
|
|
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;
|
|
}
|
|
DeleteDevEntry(pDev);
|
|
LLDnodeDelete(self->iList);
|
|
iRet = LLDnodePtr2Prev(self->iList);
|
|
if(SCGetInterrupt(self->pOwner) != eContinue)
|
|
{
|
|
self->iStatus = DEVINT;
|
|
return -1;
|
|
}
|
|
self->iStatus = DEVDONE;
|
|
break;
|
|
case HWFault: /* real HW error: burning, no net etc.. */
|
|
DeleteDevEntry(pDev);
|
|
LLDnodeDelete(self->iList);
|
|
self->iStatus = DEVERROR;
|
|
if(pDrivInt)
|
|
{
|
|
pDrivInt->iErrorCount++;
|
|
}
|
|
if(SCGetInterrupt(self->pOwner) != eContinue)
|
|
{
|
|
self->iStatus = DEVINT;
|
|
return -1;
|
|
}
|
|
break;
|
|
case HWNoBeam:
|
|
SetStatus(eOutOfBeam);
|
|
if(SCGetInterrupt(self->pOwner) != eContinue)
|
|
{
|
|
SetStatus(eEager);
|
|
self->iStatus = DEVINT;
|
|
return -1;
|
|
}
|
|
break;
|
|
case HWPause:
|
|
SetStatus(ePaused);
|
|
if(SCGetInterrupt(self->pOwner) != eContinue)
|
|
{
|
|
ContinueExecution(self);
|
|
self->iStatus = DEVINT;
|
|
return -1;
|
|
}
|
|
break;
|
|
case HWBusy:
|
|
if(pCountInt != NULL && pDrivInt != NULL)
|
|
{
|
|
SetStatus(eCountDrive);
|
|
}
|
|
else if(pCountInt != NULL && pDrivInt == NULL)
|
|
{
|
|
SetStatus(eCounting);
|
|
}
|
|
else if(pDrivInt != NULL && pCountInt == NULL)
|
|
{
|
|
SetStatus(eDriving);
|
|
}
|
|
self->iStatus = DEVBUSY;
|
|
break;
|
|
case HWPosFault: /* cannot get somewhere... */
|
|
DeleteDevEntry(pDev);
|
|
LLDnodeDelete(self->iList);
|
|
self->iStatus = DEVERROR;
|
|
if(pDrivInt)
|
|
{
|
|
pDrivInt->iErrorCount++;
|
|
}
|
|
if(SCGetInterrupt(self->pOwner) != eContinue)
|
|
{
|
|
self->iStatus = DEVINT;
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
iRet = LLDnodePtr2Next(self->iList);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
int Wait4Success(pExeList self)
|
|
{
|
|
int iRet;
|
|
assert(self);
|
|
|
|
self->iRun = 0;
|
|
|
|
/* do nothing if not running */
|
|
if(self->lTask < 0)
|
|
{
|
|
printf("Nothing to wait for....\n");
|
|
return self->iStatus;
|
|
}
|
|
|
|
/* wait for Devexec task to finish */
|
|
TaskWait(self->pTask,self->lTask);
|
|
#ifdef DEBUG
|
|
printf("Wait4Success finished\n");
|
|
#endif
|
|
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;
|
|
}
|
|
|
|
/*
|
|
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;
|
|
}
|
|
|
|
/* first the ALL case */
|
|
if(strcmp(name,"all") == 0)
|
|
{
|
|
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!!",eError);
|
|
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)
|
|
{
|
|
pDrivInt->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)
|
|
{
|
|
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData,COUNTID);
|
|
if(pCountInt)
|
|
{
|
|
iRet = pCountInt->Pause(pDev->pData,self->pOwner);
|
|
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,self->pOwner);
|
|
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;
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int ListExe(SConnection *pCon, SicsInterp *pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
return ListPending((pExeList)pData,pCon);
|
|
}
|
|
/*--------------------------------------------------------------------------
|
|
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 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;
|
|
}
|
|
|
|
iRet = CheckExeList(self);
|
|
switch(iRet)
|
|
{
|
|
case -1: /* some problem */
|
|
iInterrupt = SCGetInterrupt(self->pOwner);
|
|
if(iInterrupt != eContinue)
|
|
{
|
|
SCWrite(self->pOwner,pBueffel, eError);
|
|
if(iInterrupt > 1)
|
|
{
|
|
Interrupt2Text(iInterrupt,pInterrupt,79);
|
|
snprintf(pBueffel,131,"ERROR: interrupt %s triggered",
|
|
pInterrupt);
|
|
StopExe(self,"all");
|
|
}
|
|
#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)
|
|
{
|
|
SCWrite(self->pOwner,
|
|
"ERROR: Interrupting Current Hardware Operation",
|
|
eError);
|
|
SCSetInterrupt(self->pOwner,*iInt);
|
|
}
|
|
StopExe(self,"all");
|
|
}
|
|
}
|
|
}
|
|
/*--------------------------------------------------------------------*/
|
|
void LockDeviceExecutor(pExeList self)
|
|
{
|
|
assert(self);
|
|
self->iLock = 1;
|
|
}
|
|
/*--------------------------------------------------------------------*/
|
|
void UnlockDeviceExecutor(pExeList self)
|
|
{
|
|
assert(self);
|
|
self->iLock = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|