To remove all relevant callbacks when doing uninterest or hdbuninterest, call RemoveCallbackUsr with the relevant function, and check the pCon. This allows to discriminate normal and hdb cases. Need to check what happens when connection is closed now.
479 lines
14 KiB
C
479 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);
|
|
lID = RegisterCallback(pNew->pCall, STEND, StateInterest,
|
|
pStateMonDummyCon, NULL);
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* Context test function for callback removal
|
|
*/
|
|
int CheckConMatch(const void* context, const void* pUserData)
|
|
{
|
|
SConnection *pKon = (SConnection*) pUserData;
|
|
SConnection *pCon = (SConnection*) context;
|
|
if (VerifyConnection(pCon) && VerifyConnection(pKon)) {
|
|
if (pCon->ident == pKon->ident)
|
|
return 0;
|
|
}
|
|
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) {
|
|
RemoveCallbackUsr(self->pCall, StateInterest, CheckConMatch, pCon); /* only this one */
|
|
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);
|
|
lID = RegisterCallback(self->pCall, STPAUSE, StateInterest,
|
|
callCon, NULL);
|
|
lID = RegisterCallback(self->pCall, STCONTINUE, StateInterest,
|
|
callCon, NULL);
|
|
lID = RegisterCallback(self->pCall, STBUSY, StateInterest,
|
|
callCon, NULL);
|
|
lID = RegisterCallback(self->pCall, STEND, StateInterest,
|
|
callCon, NULL);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else if (strcmp(argv[1], "uninterest") == 0) {
|
|
RemoveCallbackUsr(self->pCall, StateInterest, CheckConMatch, pCon); /* only this one */
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else if (strcmp(argv[1], "hdbuninterest") == 0) {
|
|
RemoveCallbackUsr(self->pCall, StateHdbInterest, CheckConMatch, pCon); /* only this one */
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
} else if (strcmp(argv[1], "hdbinterest") == 0) {
|
|
RemoveCallbackUsr(self->pCall, StateHdbInterest, CheckConMatch, pCon); /* only this one */
|
|
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;
|
|
} 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;
|
|
}
|