971 lines
25 KiB
C
971 lines
25 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
|
|
|
|
Heavily restructured to use separate tasks for each action
|
|
|
|
Mark Koennecke, February 2013
|
|
|
|
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 "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);
|
|
}
|
|
|
|
|
|
/* ----------------- The Executor himself ---------------------------------*/
|
|
typedef struct __EXELIST {
|
|
pObjectDescriptor pDes;
|
|
SConnection *pOwner;
|
|
int iRun;
|
|
int iStatus;
|
|
int drivePrint;
|
|
long lTask;
|
|
long waitID;
|
|
long runID;
|
|
pTaskMan pTask;
|
|
int iLock;
|
|
pICallBack pCall;
|
|
time_t lastRun;
|
|
int paused;
|
|
int taskRunning;
|
|
int instStatus;
|
|
} 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->iRun = 0;
|
|
pRes->iStatus = DEVDONE;
|
|
pRes->pTask = pTask;
|
|
pRes->lTask = -1;
|
|
pRes->waitID = -1;
|
|
pRes->runID = -1;
|
|
pRes->iLock = 0;
|
|
pRes->drivePrint = 0;
|
|
pRes->paused = 0;
|
|
pRes->taskRunning = 0;
|
|
pRes->pCall = CreateCallBackInterface();
|
|
pRes->lastRun = time(NULL);
|
|
pRes->pDes->GetInterface = DevexecInterface;
|
|
pRes->instStatus = eEager;
|
|
return pRes;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
void DeleteExeList(void *pData)
|
|
{
|
|
pExeList self;
|
|
|
|
assert(pData);
|
|
|
|
self = (pExeList) pData;
|
|
if (self->pDes)
|
|
DeleteDescriptor(self->pDes);
|
|
ClearExecutor(self);
|
|
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, char *name, char *text)
|
|
{
|
|
char buf[128];
|
|
|
|
snprintf(buf, sizeof(buf), "%s %s", 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)
|
|
{
|
|
int iRet;
|
|
char pBueffel[132], pError[80];
|
|
pIDrivable pDrivInt = NULL;
|
|
pICountable pCountInt = NULL;
|
|
static int overwriteOwner = -1;
|
|
char *overwriteOption;
|
|
float oldVal;
|
|
long taskID;
|
|
|
|
assert(self);
|
|
assert(pDes);
|
|
assert(pCon);
|
|
|
|
/* may we? */
|
|
if (self->pOwner != NULL) {
|
|
if (SCGetIdent(pCon) != SCGetIdent(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) {
|
|
SCDeleteConnection(self->pOwner);
|
|
self->pOwner = SCCopyConnection(pCon);
|
|
} else {
|
|
SCWrite(pCon,
|
|
"ERROR: somebody else is still driving, Request rejected",
|
|
eLogError);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
if (self->iLock == 1) {
|
|
SCWrite(pCon, "ERROR: instrument is locked", eError);
|
|
return 0;
|
|
}
|
|
|
|
EndDriveTask(pData); /* BEGIN experimental: stop pending drive task for this objects immediately */
|
|
|
|
SetDevexecStatus(self,DEVDONE);
|
|
if(self->waitID < 0 && level == RUNDRIVE){
|
|
self->waitID = GetTaskGroupID(pServ->pTasker);
|
|
self->iStatus = DEVBUSY;
|
|
} else if(self->runID < 0 && level == RUNRUN){
|
|
self->runID = GetTaskGroupID(pServ->pTasker);
|
|
self->iStatus = DEVBUSY;
|
|
}
|
|
|
|
|
|
|
|
if((pDrivInt = pDes->GetInterface(pData,DRIVEID)) != NULL){
|
|
taskID = StartDriveTask(pData, pCon, name, fNew);
|
|
if(taskID > 0 && self->instStatus != eCounting){
|
|
self->instStatus = eDriving;
|
|
}
|
|
if(taskID > 0 && 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);
|
|
}
|
|
} else if(pDes->GetInterface(pData,COUNTID) != NULL){
|
|
taskID = StartCountTask(pData,pCon,name);
|
|
if(taskID > 0){
|
|
self->instStatus = eCounting;
|
|
}
|
|
} else {
|
|
SCPrintf(pCon,eLogError, "ERROR: type unkonw, cannot start %s", name);
|
|
return 0;
|
|
}
|
|
|
|
if(taskID > 0){
|
|
if(self->pOwner == NULL){
|
|
self->pOwner = SCCopyConnection(pCon);
|
|
}
|
|
self->lastRun = time(NULL);
|
|
if(level == RUNRUN){
|
|
AddTaskToGroup(pServ->pTasker, taskID, self->runID);
|
|
} else {
|
|
AddTaskToGroup(pServ->pTasker, taskID, self->waitID);
|
|
}
|
|
self->iRun = 1;
|
|
self->iStatus = DEVBUSY;
|
|
if(self->lTask < 0) {
|
|
self->lTask = TaskRegisterN(self->pTask,"devexec",
|
|
DevExecTask,
|
|
DevExecSignal,
|
|
NULL, self,TASK_PRIO_HIGH);
|
|
}
|
|
SCSetConStatus(pCon,HWBusy);
|
|
return 1;
|
|
} else {
|
|
snprintf(pBueffel,131, "ERROR: cannot start device %s", name);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
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)
|
|
{
|
|
long taskID;
|
|
pIDrivable pDrivInt = NULL;
|
|
|
|
if((pDrivInt = pDes->GetInterface(pData,DRIVEID)) != NULL){
|
|
taskID = StartDriveTask(pData, pCon, name, fNew);
|
|
} else if(pDes->GetInterface(pData,COUNTID) != NULL){
|
|
taskID = StartCountTask(pData,pCon,name);
|
|
} else {
|
|
SCPrintf(pCon,eLogError, "ERROR: type unkonw, cannot start %s", name);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
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);
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int DevExecLevelRunning(pExeList self, int level)
|
|
{
|
|
if(level == RUNRUN){
|
|
if(isTaskGroupRunning(self->pTask, self->runID)){
|
|
return 1;
|
|
}
|
|
} else if(level == RUNDRIVE){
|
|
if(isTaskGroupRunning(self->pTask, self->waitID)){
|
|
return 1;
|
|
}
|
|
}
|
|
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(isTaskIDRunning(self->pTask,self->lTask)){
|
|
TaskYield(self->pTask);
|
|
}
|
|
#ifdef DEBUG
|
|
printf("Wait4Success finished\n");
|
|
#endif
|
|
self->iRun = 0;
|
|
return self->iStatus;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------*/
|
|
long GetDevexecID(pExeList self)
|
|
{
|
|
assert(self);
|
|
|
|
return self->lTask;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int StopExe(pExeList self, char *name)
|
|
{
|
|
int interrupt = 3;
|
|
|
|
assert(self);
|
|
|
|
/* if not active, nothing to do */
|
|
if (self->pOwner == NULL ) {
|
|
self->iRun = 0;
|
|
return 1;
|
|
}
|
|
if (strcasecmp(name, "run") == 0) {
|
|
TaskSignalGroup(self->pTask, SICSINT, &interrupt, self->runID);
|
|
return 1;
|
|
}
|
|
TaskSignalGroup(self->pTask, SICSINT, &interrupt, self->waitID);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int StopExeWait(pExeList self)
|
|
{
|
|
StopExe(self, "all");
|
|
while(isTaskIDRunning(self->pTask, self->lTask)){
|
|
TaskYield(self->pTask);
|
|
}
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int PauseExecution(pExeList self)
|
|
{
|
|
int interrupt = 0;
|
|
|
|
assert(self);
|
|
|
|
if(IsCounting(self)){
|
|
TaskSignalGroup(self->pTask, IPAUSE, &interrupt, self->waitID);
|
|
TaskSignalGroup(self->pTask, IPAUSE, &interrupt, self->runID);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------
|
|
check, may be obsolete
|
|
*/
|
|
int IsCounting(pExeList self)
|
|
{
|
|
assert(self);
|
|
|
|
/* step through the list */
|
|
if(self->instStatus == eCounting){
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int ContinueExecution(pExeList self)
|
|
{
|
|
int interrupt = 0;
|
|
assert(self);
|
|
|
|
if(GetStatus() == ePaused){
|
|
TaskSignalGroup(self->pTask, CONTINUE, &interrupt, self->waitID);
|
|
TaskSignalGroup(self->pTask, CONTINUE, &interrupt, self->runID);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
void ClearExecutor(pExeList self)
|
|
{
|
|
int iRet;
|
|
|
|
assert(self);
|
|
|
|
if (self->pOwner) {
|
|
if (SCGetInterrupt(self->pOwner) > eContinue) {
|
|
self->iStatus = DEVINT;
|
|
}
|
|
SCDeleteConnection(self->pOwner);
|
|
}
|
|
self->pOwner = NULL;
|
|
self->lTask = -1;
|
|
self->waitID = -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;
|
|
|
|
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 ListPending(pExeList self, SConnection *pCon)
|
|
{
|
|
pDynString buffer;
|
|
pTaskHead it = NULL;
|
|
long id;
|
|
|
|
if(self->lTask < 0){
|
|
SCWrite(pCon,"Machine Idle",eValue);
|
|
return 1;
|
|
}
|
|
|
|
buffer = CreateDynString(128,128);
|
|
if(buffer == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory in Listpending",eError);
|
|
return 0;
|
|
}
|
|
|
|
for(it = TaskIteratorStart(self->pTask); it != NULL; it = TaskIteratorNext(it)){
|
|
id = GetGroupID(it);
|
|
if(id == self->waitID || id == self->runID){
|
|
DynStringConcat(buffer,(char *)GetTaskName(it));
|
|
DynStringConcatChar(buffer,'\n');
|
|
}
|
|
}
|
|
|
|
SCWrite(pCon,GetCharArray(buffer),eValue);
|
|
DeleteDynString(buffer);
|
|
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 = RUNRUN;
|
|
Status eOld;
|
|
pExeList self = (pExeList)pData;
|
|
|
|
eOld = GetStatus();
|
|
|
|
if(argc > 1){
|
|
if(strcmp(argv[1],"RUNDRIVE") == 0){
|
|
level = RUNDRIVE;
|
|
}
|
|
}
|
|
|
|
if(level == RUNRUN) {
|
|
while(isTaskIDRunning(self->pTask,self->lTask)){
|
|
TaskYield(self->pTask);
|
|
}
|
|
} else {
|
|
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);
|
|
self->iRun = 0;
|
|
iRet = 1;
|
|
} else if (iRet == DEVERROR) {
|
|
SCWrite(pCon, "Finished with Problems", eValue);
|
|
iRet = 1;
|
|
} else if(iRet == DEVBUSY){
|
|
/*
|
|
some other level may still be running
|
|
*/
|
|
if(level == RUNRUN){
|
|
self->iRun = 0;
|
|
}
|
|
SCWrite(pCon, "Level done", eValue);
|
|
iRet = 1;
|
|
}
|
|
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;
|
|
self = (pExeList) pData;
|
|
|
|
assert(self != NULL);
|
|
|
|
if(isTaskGroupRunning(self->pTask,self->waitID)
|
|
|| isTaskGroupRunning(self->pTask,self->runID)){
|
|
self->iStatus = DEVBUSY;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
We are done, clean up
|
|
*/
|
|
self->waitID = -1;
|
|
self->lTask = -1;
|
|
self->iRun = 0;
|
|
self->instStatus = eEager;
|
|
/*
|
|
This is sort of unclean. Setting DEVERROR has to be done in the
|
|
device task function as it is the only one that knows about this.
|
|
Interrupts always have priority, thus they are dealt with here.
|
|
*/
|
|
if(SCGetInterrupt(self->pOwner) != eContinue){
|
|
self->iStatus = DEVINT;
|
|
} else {
|
|
if(self->iStatus != DEVERROR){
|
|
self->iStatus = DEVDONE;
|
|
}
|
|
}
|
|
SCDeleteConnection(self->pOwner);
|
|
self->pOwner = NULL;
|
|
|
|
return 0;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
void DevExecSignal(void *pEL, int iSignal, void *pSigData)
|
|
{
|
|
int *iInt;
|
|
pExeList self = NULL;
|
|
SConnection *pCon = NULL;
|
|
|
|
self = (pExeList) pEL;
|
|
assert(self);
|
|
|
|
TaskSignalGroup(self->pTask,iSignal, pSigData, self->waitID);
|
|
}
|
|
/*--------------------------------------------------------------------*/
|
|
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;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
void SetDevexecStatus(pExeList pExe, int code)
|
|
{
|
|
if(code >= 0 || code <= DEVBUSY){
|
|
pExe->iStatus = code;
|
|
}
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
int GetDevExecInstStatus(pExeList self)
|
|
{
|
|
if(self->lTask < 0){
|
|
return eEager;
|
|
} else {
|
|
return self->instStatus;
|
|
}
|
|
}
|