Files
sics/statemon.c
2014-06-11 17:12:46 +10:00

475 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)
{
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];
pSicsVariable pVar = NULL;
if (pCon == NULL || !SCisConnected(pCon)) {
return -1;
}
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);
SCWrite(pCon, buffer, eWarning);
}
if (iEvent == STEND) {
snprintf(buffer, 255, "FINISH = %s", device);
SCWrite(pCon, buffer, eWarning);
}
if (iEvent == STPAUSE) {
snprintf(buffer, 255, "PAUSE = %s", device);
SCWrite(pCon, buffer, eWarning);
}
if (iEvent == STCONTINUE) {
snprintf(buffer, 255, "CONTINUE = %s", device);
SCWrite(pCon, buffer, eWarning);
}
if (iEvent == STBUSY) {
snprintf(buffer, 255, "BUSY = %s", device);
SCWrite(pCon, buffer, eWarning);
}
if (iEvent == STIDLE) {
snprintf(buffer, 255, "IDLE = %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);
}
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, 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: failed to locate scan object", eError);
} else {
target = GetCallbackInterface(pPtr);
assert(target != NULL);
RegisterCallback(target, SCANSTART, StateMonScanInterest, pNew,
NULL);
RegisterCallback(target, SCANEND, StateMonScanInterest, pNew, NULL);
}
}
/* Make dummy connection for SUID (instrument state id) */
pStateMonDummyCon = SCCreateDummyConnection(pSics);
lID = RegisterCallback(pNew->pCall, STSTART, StateInterest,
pStateMonDummyCon, NULL);
SCRegister(pStateMonDummyCon, pSics, pNew->pCall, lID);
lID = RegisterCallback(pNew->pCall, 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;
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, NULL);
SCRegister(pCon, pSics, self->pCall, lID);
lID = RegisterCallback(self->pCall, STPAUSE, StateInterest,
callCon, NULL);
SCRegister(pCon, pSics, self->pCall, lID);
lID = RegisterCallback(self->pCall, STCONTINUE, StateInterest,
callCon, NULL);
SCRegister(pCon, pSics, self->pCall, lID);
lID = RegisterCallback(self->pCall, STBUSY, StateInterest,
callCon, NULL);
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);
SCUnregisterID(pCon, 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);
/* TODO: why not SCRegister(pCon, pSics, self->pCall, lID); */
lID = RegisterCallback(self->pCall, STEND, StateHdbInterest,
callCon, NULL);
/* TODO: why not 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;
}