One typo and forgetting to clear a temporary variable meant that the list of candidates for removal never shrank while pruning reflectometer/config/motors/sct_batmotor.tcl The beam attenuator is on axis D not A. Also provide statemon feedback, "busy" or "idle" sans/config/velsel/velsel.tcl Update velocity selector parameters for NVS 43 SICS-374 sans/config/velsel/sct_velsel.tcl Set velocity selector identifier script_context_util.tcl Don't override the "klass' attribute, just make sure that it matches the hdb klass property if it's defined. event.h and statemon.c Added statemon BUSY and IDLE events for the scbat because it when it oscillates it's busy doing something. r2875 | ffr | 2010-01-22 20:41:36 +1100 (Fri, 22 Jan 2010) | 18 lines
436 lines
14 KiB
C
436 lines
14 KiB
C
/**
|
|
* This is a state monitor. It collects all the start and stop messages
|
|
* from the device executor and from scan and batch commands. Clients can
|
|
* listen to this in order to figure out what is actually going on in a
|
|
* given SICS installation. This might in the end supersede the status code
|
|
* management in status.c
|
|
*
|
|
* copyright: see file COPYRIGHT
|
|
*
|
|
* Mark Koennecke, January 2007
|
|
*/
|
|
#include <sics.h>
|
|
#include "exeman.h"
|
|
#include "scan.h"
|
|
#include "scan.i"
|
|
#include "stptok.h"
|
|
#include "statemon.h"
|
|
#include "sicshipadaba.h"
|
|
#include "sicsvar.h"
|
|
|
|
#define SICS_SUID "sics_suid"
|
|
pICallBack statemon_cbinterface = NULL;
|
|
/*==========================================================================*/
|
|
typedef struct __STATEMON {
|
|
pObjectDescriptor pDes;
|
|
pICallBack pCall;
|
|
}StateMon;
|
|
SConnection *pStateMonDummyCon = NULL;
|
|
/*============================ Callbacks =================================*/
|
|
static int DevexecCallback(int iEvent, void *text, void *pData,
|
|
commandContext cc){
|
|
char pDevice[132];
|
|
int eventCode;
|
|
pStateMon self = (pStateMon)pData;
|
|
|
|
memset(pDevice,0,132);
|
|
if(iEvent == DRIVSTAT){
|
|
stptok(text,pDevice,131," ");
|
|
if(strstr(text,"started") != NULL){
|
|
eventCode = STSTART;
|
|
} else if(strstr(text,"finished") != NULL) {
|
|
eventCode = STEND;
|
|
} else {
|
|
printf("Unrecognized event text from devexec in statemon.c: %s\n",
|
|
(char *)text);
|
|
return 0;
|
|
}
|
|
if(self != NULL){
|
|
InvokeCallBack(self->pCall,eventCode,pDevice);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
static int StateMonScanInterest(int iEvent, void *pEventData, void *pUser,
|
|
commandContext cc){
|
|
pScanData pScan = NULL;
|
|
pStateMon self = (pStateMon)pUser;
|
|
|
|
pScan = (pScanData)pEventData;
|
|
|
|
if(pScan == NULL || self == NULL){
|
|
printf("Bad StateMonScanInterst in statemon\n");
|
|
return 0;
|
|
}
|
|
|
|
if(iEvent == SCANSTART){
|
|
InvokeCallBack(self->pCall,STSTART,pScan->objectName);
|
|
return 1;
|
|
}else if(iEvent == SCANEND){
|
|
InvokeCallBack(self->pCall,STEND,pScan->objectName);
|
|
return 1;
|
|
}
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int ExeCallback(int iEvent, void *pEvent, void *pUser,
|
|
commandContext cc){
|
|
pStateMon self = (pStateMon)pUser;
|
|
char *name = (char *)pEvent;
|
|
char pBueffel[131];
|
|
|
|
if(self == NULL || name == NULL){
|
|
printf("Bad ExeCallback in statemon\n");
|
|
return 0;
|
|
}
|
|
|
|
if(iEvent == BATCHSTART){
|
|
snprintf(pBueffel,131,"exe %s",name);
|
|
InvokeCallBack(self->pCall,STSTART,pBueffel);
|
|
return 1;
|
|
}
|
|
if(iEvent == BATCHEND){
|
|
snprintf(pBueffel,131,"exe %s",name);
|
|
InvokeCallBack(self->pCall,STEND,pBueffel);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
/*=============== user callbacks ============================================*/
|
|
static int StateInterest(int iEvent, void *pEvent, void *pUser,
|
|
commandContext cc){
|
|
SConnection *pCon = (SConnection *)pUser;
|
|
char *device = (char *)pEvent;
|
|
char buffer[256];
|
|
pSicsVariable pVar = NULL;
|
|
|
|
if( pCon == NULL || device == NULL) {
|
|
printf("Bad StateInterest in statemon\n");
|
|
return 0;
|
|
} else if (pCon == pStateMonDummyCon) {
|
|
if(iEvent == STSTART){
|
|
snprintf(buffer,255,"SUID MSG STARTED = %s", device);
|
|
SCWrite(pStateMonDummyCon,buffer,eError);
|
|
}
|
|
if(iEvent == STEND){
|
|
snprintf(buffer,255,"SUID MSG FINISH = %s", device);
|
|
SCWrite(pStateMonDummyCon,buffer,eError);
|
|
}
|
|
pVar = (pSicsVariable)FindCommandData(pServ->pSics,SICS_SUID,"SicsVariable");
|
|
if (pVar == NULL) {
|
|
SCWrite(pStateMonDummyCon,"ERROR: StateMon.c: Could not find SUID SicsVariable",eError);
|
|
return 0;
|
|
}
|
|
(pVar->iVal)++;
|
|
InvokeCallBack(pVar->pCall, VALUECHANGE, pVar);
|
|
} else {
|
|
if(iEvent == STSTART){
|
|
snprintf(buffer,255,"STARTED = %s", device);
|
|
SCWriteInContext(pCon,buffer,eWarning,cc);
|
|
}
|
|
if(iEvent == STEND){
|
|
snprintf(buffer,255,"FINISH = %s", device);
|
|
SCWriteInContext(pCon,buffer,eWarning,cc);
|
|
}
|
|
if(iEvent == STPAUSE){
|
|
snprintf(buffer,255,"PAUSE = %s", device);
|
|
SCWriteInContext(pCon,buffer,eWarning,cc);
|
|
}
|
|
if(iEvent == STCONTINUE){
|
|
snprintf(buffer,255,"CONTINUE = %s", device);
|
|
SCWriteInContext(pCon,buffer,eWarning,cc);
|
|
}
|
|
if(iEvent == STBUSY){
|
|
snprintf(buffer,255,"BUSY = %s", device);
|
|
SCWriteInContext(pCon,buffer,eWarning,cc);
|
|
}
|
|
if(iEvent == STIDLE){
|
|
snprintf(buffer,255,"IDLE = %s", device);
|
|
SCWriteInContext(pCon,buffer,eWarning,cc);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static pHdb recurseInterestNode(pHdb current, char *pDevice){
|
|
char pSicsdev[131], pAlias[132];
|
|
pHdb result = NULL;
|
|
char *alias = NULL, *pPtr = NULL;
|
|
|
|
memset(pSicsdev,0,132);
|
|
memset(pAlias,0,132);
|
|
if(current != NULL){
|
|
if(GetHdbProperty(current,"sicsdev",pSicsdev,131) != 0){
|
|
strtolower(pSicsdev);
|
|
if(strcmp(pSicsdev,pDevice) == 0){
|
|
return current;
|
|
}
|
|
/*
|
|
* try to look for aliases, too
|
|
*/
|
|
alias = FindAliases(pServ->pSics,pSicsdev);
|
|
pPtr = alias;
|
|
if(pPtr != NULL){
|
|
while((pPtr = stptok(pPtr,pAlias,131,",")) != NULL){
|
|
if(strcmp(pAlias,pDevice) == 0){
|
|
return current;
|
|
}
|
|
}
|
|
if(alias != NULL){
|
|
free(alias);
|
|
}
|
|
}
|
|
}
|
|
current = current->child;
|
|
while(current != NULL){
|
|
result = recurseInterestNode(current, pDevice);
|
|
if(result != NULL){
|
|
return result;
|
|
}
|
|
current = current->next;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static pHdb locateInterestNode(char *device){
|
|
char pDevice[132], pSicsdev[132];
|
|
pHdb current = NULL, result = NULL;
|
|
|
|
memset(pDevice,0,132);
|
|
memset(pSicsdev,0,132);
|
|
|
|
/*
|
|
* this is to strip off exes batch file name
|
|
*/
|
|
stptok(device,pDevice,131," ");
|
|
strtolower(pDevice);
|
|
|
|
current = GetHipadabaRoot();
|
|
return recurseInterestNode(current,pDevice);
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static int StateHdbInterest(int iEvent, void *pEvent, void *pUser,
|
|
commandContext cc){
|
|
SConnection *pCon = (SConnection *)pUser;
|
|
char *device = (char *)pEvent, *path = NULL;
|
|
char buffer[1024];
|
|
pHdb node = NULL;
|
|
|
|
if(pCon == NULL || device == NULL){
|
|
printf("Bad StateHdbInterest in statemon\n");
|
|
return 0;
|
|
}
|
|
node = locateInterestNode(device);
|
|
if(node != NULL){
|
|
path = GetHipadabaPath(node);
|
|
if(iEvent == STSTART){
|
|
snprintf(buffer,1024,"%s STARTED", path);
|
|
SCWriteInContext(pCon,buffer,eWarning,cc);
|
|
}
|
|
if(iEvent == STEND){
|
|
snprintf(buffer,1024,"%s FINISH", path);
|
|
SCWriteInContext(pCon,buffer,eWarning,cc);
|
|
}
|
|
if(path != NULL){
|
|
free(path);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
/*====================== interpreter interface ==============================*/
|
|
static void killStateMon(void *pData){
|
|
pStateMon self = NULL;
|
|
|
|
self = (pStateMon)pData;
|
|
if(self != NULL){
|
|
if(self->pDes != NULL){
|
|
DeleteDescriptor(self->pDes);
|
|
}
|
|
if(self->pCall != NULL){
|
|
DeleteCallBackInterface(self->pCall);
|
|
}
|
|
if(pStateMonDummyCon != NULL) {
|
|
SCDeleteConnection(pStateMonDummyCon);
|
|
}
|
|
free(self);
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
int StateMonFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
|
|
int argc, char *argv[]){
|
|
long lID;
|
|
pStateMon pNew = NULL;
|
|
commandContext cc;
|
|
pICallBack target = NULL;
|
|
void *pPtr = NULL, *exe = NULL, *pDevexec = NULL;
|
|
pSicsVariable pRes = NULL;
|
|
|
|
exe = FindCommandData(pSics,"exe", "ExeManager");
|
|
pDevexec = FindCommandData(pSics,"stopexe","DeviceExecutor");
|
|
if(exe == NULL || pDevexec == NULL){
|
|
SCWrite(pCon,
|
|
"ERROR: both the device executor and the batch file module must be installed before initialising statemon",
|
|
eError);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* generate data structures
|
|
*/
|
|
strcpy(cc.deviceID,"statemon");
|
|
cc.transID = -120;
|
|
pNew = (pStateMon)malloc(sizeof(StateMon));
|
|
if(pNew == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory creating StateMon",eError);
|
|
return 0;
|
|
}
|
|
memset(pNew,0,sizeof(StateMon));
|
|
pNew->pDes = CreateDescriptor("statemon");
|
|
pNew->pCall = CreateCallBackInterface();
|
|
statemon_cbinterface = pNew->pCall;
|
|
if(pNew->pDes == NULL || pNew->pCall == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory creating StateMon",eError);
|
|
return 0;
|
|
}
|
|
/*
|
|
* register callbacks
|
|
*/
|
|
target = GetCallbackInterface(pDevexec);
|
|
assert(target != NULL);
|
|
RegisterCallback(target,cc,DRIVSTAT,DevexecCallback,pNew,NULL);
|
|
target = GetCallbackInterface(exe);
|
|
assert(target != NULL);
|
|
RegisterCallback(target,cc,BATCHSTART,ExeCallback,pNew,NULL);
|
|
RegisterCallback(target,cc,BATCHEND,ExeCallback,pNew,NULL);
|
|
|
|
if(argc > 1) {
|
|
pPtr = FindCommandData(pSics,argv[1],"ScanObject");
|
|
if(pPtr == NULL){
|
|
SCWrite(pCon,"ERROR: failed to locate scan object",eError);
|
|
} else {
|
|
target = GetCallbackInterface(pPtr);
|
|
assert(target != NULL);
|
|
RegisterCallback(target,cc,SCANSTART,StateMonScanInterest,pNew,NULL);
|
|
RegisterCallback(target,cc,SCANEND,StateMonScanInterest,pNew,NULL);
|
|
}
|
|
}
|
|
/* Make dummy connection for SUID (instrument state id) */
|
|
pStateMonDummyCon = SCCreateDummyConnection(pSics);
|
|
lID = RegisterCallback(pNew->pCall, SCGetContext(pStateMonDummyCon),STSTART, StateInterest, pStateMonDummyCon, NULL);
|
|
SCRegister(pStateMonDummyCon,pSics, pNew->pCall,lID);
|
|
lID = RegisterCallback(pNew->pCall, SCGetContext(pStateMonDummyCon),STEND, StateInterest, pStateMonDummyCon, NULL);
|
|
SCRegister(pStateMonDummyCon,pSics, pNew->pCall,lID);
|
|
pRes = VarCreate(usInternal,veInt,SICS_SUID);
|
|
AddCommand(pSics,SICS_SUID,VarWrapper,(KillFunc)VarKill,pRes);
|
|
/*
|
|
* TODO: add kill functions
|
|
*/
|
|
AddCommand(pSics,"statemon",StateMonAction,killStateMon,pNew);
|
|
return 1;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
int StateMonAction(SConnection *pCon, SicsInterp *pSics, void *pData,
|
|
int argc, char *argv[]){
|
|
long lID;
|
|
int i;
|
|
pStateMon self = NULL;
|
|
|
|
self = (pStateMon)pData;
|
|
assert(self != NULL);
|
|
|
|
if(argc < 2){
|
|
SCWrite(pCon,"ERROR: not enough arguments to statemon",eError);
|
|
return 0;
|
|
}
|
|
strtolower(argv[1]);
|
|
if(strcmp(argv[1],"interest") == 0){
|
|
lID = RegisterCallback(self->pCall, SCGetContext(pCon),STSTART, StateInterest,
|
|
pCon, NULL);
|
|
SCRegister(pCon,pSics, self->pCall,lID);
|
|
lID = RegisterCallback(self->pCall, SCGetContext(pCon),STEND, StateInterest,
|
|
pCon, NULL);
|
|
SCRegister(pCon,pSics, self->pCall,lID);
|
|
lID = RegisterCallback(self->pCall, SCGetContext(pCon),STPAUSE, StateInterest,
|
|
pCon, NULL);
|
|
SCRegister(pCon,pSics, self->pCall,lID);
|
|
lID = RegisterCallback(self->pCall, SCGetContext(pCon),STCONTINUE, StateInterest,
|
|
pCon, NULL);
|
|
SCRegister(pCon,pSics, self->pCall,lID);
|
|
lID = RegisterCallback(self->pCall, SCGetContext(pCon),STBUSY, StateInterest,
|
|
pCon, NULL);
|
|
SCRegister(pCon,pSics, self->pCall,lID);
|
|
lID = RegisterCallback(self->pCall, SCGetContext(pCon),STIDLE, StateInterest,
|
|
pCon, NULL);
|
|
SCRegister(pCon,pSics, self->pCall,lID);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else if(strcmp(argv[1],"uninterest") == 0) {
|
|
for(i = 0; i < 2; i++){
|
|
lID = SCgetCallbackID(pCon,self->pCall);
|
|
if(lID >= 0){
|
|
RemoveCallback(self->pCall,lID);
|
|
SCUnregisterID(pCon,lID);
|
|
}
|
|
}
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else if(strcmp(argv[1],"hdbinterest") == 0){
|
|
lID = RegisterCallback(self->pCall, SCGetContext(pCon),STSTART, StateHdbInterest,
|
|
pCon, NULL);
|
|
SCRegister(pCon,pSics, self->pCall,lID);
|
|
lID = RegisterCallback(self->pCall, SCGetContext(pCon),STEND, StateHdbInterest,
|
|
pCon, NULL);
|
|
SCRegister(pCon,pSics, self->pCall,lID);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else if(strcmp(argv[1],"start") == 0) {
|
|
if(argc > 2){
|
|
InvokeCallBack(self->pCall,STSTART,argv[2]);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
} else if(strcmp(argv[1],"stop") == 0) {
|
|
if(argc > 2){
|
|
InvokeCallBack(self->pCall,STEND,argv[2]);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
} else if(strcmp(argv[1],"pause") == 0) {
|
|
if(argc > 2){
|
|
InvokeCallBack(self->pCall,STPAUSE,argv[2]);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
} else if(strcmp(argv[1],"continue") == 0) {
|
|
if(argc > 2){
|
|
InvokeCallBack(self->pCall,STCONTINUE,argv[2]);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
} else if(strcmp(argv[1],"busy") == 0) {
|
|
if(argc > 2){
|
|
InvokeCallBack(self->pCall,STBUSY,argv[2]);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
} else if(strcmp(argv[1],"idle") == 0) {
|
|
if(argc > 2){
|
|
InvokeCallBack(self->pCall,STIDLE,argv[2]);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
SCWrite(pCon,"ERROR: keyword not recognized",eError);
|
|
return 0;
|
|
}
|