Files
sics/devexec.c
2007-11-27 13:36:15 +00:00

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;
}