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
370 lines
10 KiB
C
370 lines
10 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
|
|
* managment 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"
|
|
/*==========================================================================*/
|
|
typedef struct __STATEMON {
|
|
pObjectDescriptor pDes;
|
|
pICallBack pCall;
|
|
} StateMon;
|
|
/*============================ Callbacks =================================*/
|
|
static int DevexecCallback(int iEvent, void *text, void *pData)
|
|
{
|
|
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)
|
|
{
|
|
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)
|
|
{
|
|
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)
|
|
{
|
|
SConnection *pCon = (SConnection *) pUser;
|
|
char *device = (char *) pEvent;
|
|
char buffer[256];
|
|
|
|
if (pCon == NULL || !SCisConnected(pCon)) {
|
|
return -1;
|
|
}
|
|
|
|
if (pCon == NULL || device == NULL) {
|
|
printf("Bad StateInterest in statemon\n");
|
|
return 0;
|
|
}
|
|
if (iEvent == STSTART) {
|
|
snprintf(buffer, 255, "STARTED = %s", device);
|
|
SCWrite(pCon, buffer, eWarning);
|
|
}
|
|
if (iEvent == STEND) {
|
|
snprintf(buffer, 255, "FINISH = %s", device);
|
|
SCWrite(pCon, buffer, eWarning);
|
|
}
|
|
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)
|
|
{
|
|
SConnection *pCon = (SConnection *) pUser;
|
|
char *device = (char *) pEvent, *path = NULL;
|
|
char buffer[1024];
|
|
pHdb node = NULL;
|
|
|
|
if (pCon == NULL || !SCisConnected(pCon)) {
|
|
return -1;
|
|
}
|
|
|
|
if (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);
|
|
SCWrite(pCon, buffer, eWarning);
|
|
}
|
|
if (iEvent == STEND) {
|
|
snprintf(buffer, 1024, "%s FINISH", path);
|
|
SCWrite(pCon, buffer, eWarning);
|
|
}
|
|
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);
|
|
}
|
|
free(self);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
int StateMonFactory(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pStateMon pNew = NULL;
|
|
commandContext cc;
|
|
pICallBack target = NULL;
|
|
void *pPtr = NULL, *exe = NULL, *pDevexec = 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();
|
|
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, DRIVSTAT, DevexecCallback, pNew, NULL);
|
|
target = GetCallbackInterface(exe);
|
|
assert(target != NULL);
|
|
RegisterCallback(target, BATCHSTART, ExeCallback, pNew, NULL);
|
|
RegisterCallback(target, BATCHEND, ExeCallback, pNew, NULL);
|
|
|
|
if (argc > 1) {
|
|
pPtr = FindCommandData(pSics, argv[1], "ScanObject");
|
|
if (pPtr == NULL) {
|
|
SCWrite(pCon, "ERROR: failked to locate scan object", eError);
|
|
} else {
|
|
target = GetCallbackInterface(pPtr);
|
|
assert(target != NULL);
|
|
RegisterCallback(target, SCANSTART, StateMonScanInterest, pNew,
|
|
NULL);
|
|
RegisterCallback(target, SCANEND, StateMonScanInterest, pNew, NULL);
|
|
}
|
|
}
|
|
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;
|
|
SConnection *callCon = 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) {
|
|
callCon = SCCopyConnection(pCon);
|
|
if (callCon == NULL) {
|
|
SCWrite(pCon, "ERROR: out of memory registering interest", eError);
|
|
return 0;
|
|
}
|
|
lID = RegisterCallback(self->pCall, STSTART, StateInterest,
|
|
callCon, SCDeleteConnection);
|
|
SCRegister(pCon, pSics, self->pCall, lID);
|
|
lID = RegisterCallback(self->pCall, STEND, StateInterest,
|
|
callCon, 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);
|
|
}
|
|
}
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else if (strcmp(argv[1], "hdbinterest") == 0) {
|
|
callCon = SCCopyConnection(pCon);
|
|
if (callCon == NULL) {
|
|
SCWrite(pCon, "ERROR: out of memory registering interest", eError);
|
|
return 0;
|
|
}
|
|
lID = RegisterCallback(self->pCall, STSTART, StateHdbInterest,
|
|
callCon, SCDeleteConnection);
|
|
lID = RegisterCallback(self->pCall, STEND, StateHdbInterest,
|
|
callCon, NULL);
|
|
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;
|
|
}
|
|
|
|
SCWrite(pCon, "ERROR: keyword not recognized", eError);
|
|
return 0;
|
|
}
|