- added scriptcontext.h
- killing a node using sct should now be safe - sctdrive adapter object might be dynamic - default for the checkstatus script: returning the status property - introduced <sctcon> unpoll - changed <sctcon> queuecon to <sctcon> send - some more improvements in sct
This commit is contained in:
251
scriptcontext.c
251
scriptcontext.c
@@ -13,6 +13,7 @@
|
||||
#include "devser.h"
|
||||
#include "ascon.h"
|
||||
#include "macro.h"
|
||||
#include "scriptcontext.h"
|
||||
|
||||
|
||||
#define MAX_HDB_PATH 1024
|
||||
@@ -30,20 +31,20 @@ typedef struct ScriptContext {
|
||||
ContextItem *base;
|
||||
} ScriptContext;
|
||||
|
||||
typedef struct SctController {
|
||||
struct SctController {
|
||||
DevSer *devser;
|
||||
Hdb *node; /* the controller node */
|
||||
SCStore *conn;
|
||||
int verbose;
|
||||
} SctController;
|
||||
};
|
||||
|
||||
/* action data and write callback data */
|
||||
typedef struct SctData {
|
||||
int writable;
|
||||
char *name;
|
||||
SctController *controller;
|
||||
SCStore *conCtx;
|
||||
int answered;
|
||||
Hdb *node; /* back link used by SctMatchWrite/SctMatchPoll */
|
||||
Hdb *node;
|
||||
} SctData;
|
||||
|
||||
static ScriptContext *sct = NULL;
|
||||
@@ -206,9 +207,13 @@ int SctCommand(SConnection *con, SicsInterp *sics, void *object,
|
||||
}
|
||||
SCWrite(con, val, eValue);
|
||||
} else { /* set case */
|
||||
val = Arg2Tcl(argc-2, argv+2, value, sizeof value);
|
||||
SetProp(node, cNode, argv[1], val);
|
||||
if (val != NULL && val != value) free(val);
|
||||
if (argc == 3) {
|
||||
SetProp(node, cNode, argv[1], argv[2]);
|
||||
} else {
|
||||
val = Arg2Tcl(argc-2, argv+2, value, sizeof value);
|
||||
SetProp(node, cNode, argv[1], val);
|
||||
if (val != NULL && val != value) free(val);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -289,10 +294,6 @@ static char *SctActionHandler(void *actionData, char *lastReply) {
|
||||
if (currentCon && ! data->answered) {
|
||||
SCWrite(con, "o.k.", eValue);
|
||||
}
|
||||
if (data->conCtx != NULL) {
|
||||
SCStoreFree(data->conCtx);
|
||||
data->conCtx = NULL;
|
||||
}
|
||||
goto finish;
|
||||
}
|
||||
SetProp(node, controller->node, "state", state);
|
||||
@@ -301,18 +302,26 @@ static char *SctActionHandler(void *actionData, char *lastReply) {
|
||||
if (controller->verbose) {
|
||||
SCPrintf(con, eWarning, "send : %s", send);
|
||||
}
|
||||
goto quit;
|
||||
if (currentCon) {
|
||||
SCStorePop(currentCon);
|
||||
} else {
|
||||
SCStorePop(controller->conn);
|
||||
}
|
||||
return send;
|
||||
}
|
||||
}
|
||||
SCPrintf(con, eError, "ERROR: too many quick scripts chained");
|
||||
finish:
|
||||
SetProp(node, controller->node, "state", "idle");
|
||||
quit:
|
||||
if (currentCon) {
|
||||
SCStorePop(currentCon);
|
||||
} else {
|
||||
SCStorePop(controller->conn);
|
||||
}
|
||||
if (data->conCtx != NULL) {
|
||||
SCStoreFree(data->conCtx);
|
||||
data->conCtx = NULL;
|
||||
}
|
||||
return send;
|
||||
}
|
||||
|
||||
@@ -328,6 +337,13 @@ static char *SctWriteHandler(void *actionData, char *lastReply) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static int SctMatchNode(void *vNode, void *vData) {
|
||||
Hdb *node = vNode;
|
||||
SctData *d = vData;
|
||||
|
||||
return node == d->node;
|
||||
}
|
||||
|
||||
static hdbCallbackReturn SctMainCallback(Hdb *node, void *userData,
|
||||
hdbMessage *msg) {
|
||||
SctController *controller = userData;
|
||||
@@ -356,6 +372,8 @@ static hdbCallbackReturn SctMainCallback(Hdb *node, void *userData,
|
||||
}
|
||||
km = GetHdbKillNodeMessage(msg);
|
||||
if (km != NULL) {
|
||||
/* unschedule all actions related to this node */
|
||||
DevUnschedule(controller->devser, node, SctActionHandler, SctMatchNode);
|
||||
CleanStack(node);
|
||||
return hdbContinue;
|
||||
}
|
||||
@@ -378,6 +396,7 @@ static hdbCallbackReturn SctActionCallback(Hdb *node, void *userData,
|
||||
hdbDataSearch *dsm;
|
||||
hdbDataMessage *mm;
|
||||
hdbPtrMessage *pm;
|
||||
hdbMessage *km;
|
||||
SctData *data = userData;
|
||||
Hdb *target;
|
||||
char *script;
|
||||
@@ -410,7 +429,7 @@ static hdbCallbackReturn SctActionCallback(Hdb *node, void *userData,
|
||||
}
|
||||
|
||||
mm = GetHdbSetMessage(msg);
|
||||
if (mm != NULL && data->writable) {
|
||||
if (mm != NULL) {
|
||||
con = mm->callData;
|
||||
|
||||
/* set target value */
|
||||
@@ -432,7 +451,10 @@ static hdbCallbackReturn SctActionCallback(Hdb *node, void *userData,
|
||||
writeprio = GetProp(node, data->controller->node, "writeprio");
|
||||
if (writeprio != NULL) {
|
||||
prio = DevText2Prio(writeprio);
|
||||
if (prio < 0) prio = WritePRIO;
|
||||
if (prio == NullPRIO) {
|
||||
SCPrintf(con, eError, "ERROR: unknown priority: %s", writeprio);
|
||||
prio = WritePRIO;
|
||||
}
|
||||
} else {
|
||||
prio = WritePRIO;
|
||||
}
|
||||
@@ -449,6 +471,7 @@ static hdbCallbackReturn SctActionCallback(Hdb *node, void *userData,
|
||||
data->answered = 0;
|
||||
DevQueue(data->controller->devser, data, prio,
|
||||
SctWriteHandler, SctMatch, NULL);
|
||||
/* no kill function in DevQueue: data is owned by the node (callback list) */
|
||||
return hdbContinue;
|
||||
}
|
||||
|
||||
@@ -469,37 +492,53 @@ static hdbCallbackReturn SctActionCallback(Hdb *node, void *userData,
|
||||
return hdbContinue;
|
||||
}
|
||||
|
||||
static char *ParText(Hdb *cmdNode, char *name) {
|
||||
static char *ParText(Hdb *cmdNode, char *name,
|
||||
int nPar, char *defaultValue) {
|
||||
Hdb *par;
|
||||
|
||||
par = GetHipadabaNode(cmdNode, name);
|
||||
if (par && par->value.dataType == HIPTEXT) {
|
||||
return par->value.v.text;
|
||||
}
|
||||
return "<undefined>";
|
||||
}
|
||||
|
||||
static double ParValue(Hdb *cmdNode, char *name) {
|
||||
Hdb *par;
|
||||
|
||||
par = GetHipadabaNode(cmdNode, name);
|
||||
if (par) {
|
||||
switch (par->value.dataType) {
|
||||
case HIPINT: return par->value.v.intValue;
|
||||
case HIPFLOAT: return par->value.v.doubleValue;
|
||||
for (par = cmdNode->child; nPar > 0 && par != NULL;
|
||||
par = par->next, nPar--) {
|
||||
if (strcasecmp(par->name, name) == 0) {
|
||||
if (par->value.dataType == HIPTEXT) {
|
||||
return par->value.v.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -999;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
void SctKillData(void *d) {
|
||||
static double ParValue(Hdb *cmdNode, char *name,
|
||||
int nPar, double defaultValue) {
|
||||
Hdb *par;
|
||||
|
||||
for (par = cmdNode->child; nPar > 0 && par != NULL;
|
||||
par = par->next, nPar--) {
|
||||
if (strcasecmp(par->name, name) == 0) {
|
||||
switch (par->value.dataType) {
|
||||
case HIPINT: return par->value.v.intValue;
|
||||
case HIPFLOAT: return par->value.v.doubleValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
static void SctKillData(void *d) {
|
||||
SctData *data = d;
|
||||
|
||||
if (data->name) free(data->name);
|
||||
if (data->conCtx) SCStoreFree(data->conCtx);
|
||||
free(data);
|
||||
}
|
||||
|
||||
void SctAddPollNode(SctController *controller, Hdb *node, double interval,
|
||||
static void SctKillCBData(void *d) {
|
||||
SctData *data = d;
|
||||
|
||||
DevRemoveAction(data->controller->devser, data);
|
||||
SctKillData(d);
|
||||
}
|
||||
|
||||
int SctAddPollNode(SctController *controller, Hdb *node, double interval,
|
||||
DevPrio prio, char *action) {
|
||||
SctData *data;
|
||||
hdbCallback *cb;
|
||||
@@ -508,22 +547,18 @@ void SctAddPollNode(SctController *controller, Hdb *node, double interval,
|
||||
cb = MakeHipadabaCallback(SctMainCallback, controller, NULL);
|
||||
assert(cb);
|
||||
AppendHipadabaCallback(node, cb);
|
||||
SetHdbProperty(node,"geterror","Not read yet");
|
||||
}
|
||||
|
||||
actionCallback.name = action;
|
||||
data = FindHdbCallbackData(node, &actionCallback);
|
||||
if (data == NULL) {
|
||||
data = calloc(1, sizeof(*data));
|
||||
assert(data);
|
||||
data->controller = controller;
|
||||
data->node = node;
|
||||
data->writable = 0;
|
||||
data->conCtx = NULL;
|
||||
data->name = strdup(action);
|
||||
}
|
||||
data = calloc(1, sizeof(*data));
|
||||
assert(data);
|
||||
data->controller = controller;
|
||||
data->node = node;
|
||||
data->conCtx = NULL;
|
||||
data->name = strdup(action);
|
||||
|
||||
DevSchedule(controller->devser, data, prio, interval,
|
||||
SctActionHandler, SctMatch, NULL);
|
||||
return DevSchedule(controller->devser, data, prio, interval,
|
||||
SctActionHandler, SctMatch, SctKillData);
|
||||
|
||||
}
|
||||
|
||||
@@ -535,6 +570,7 @@ static int SctPollCmd(pSICSOBJ ccmd, SConnection *con,
|
||||
char *path;
|
||||
DevPrio prio;
|
||||
char *action;
|
||||
char *prioText;
|
||||
|
||||
if(nPar < 1){
|
||||
SCPrintf(con,eError,
|
||||
@@ -543,21 +579,63 @@ static int SctPollCmd(pSICSOBJ ccmd, SConnection *con,
|
||||
return 0;
|
||||
}
|
||||
controller = ccmd->pPrivate;
|
||||
path = ParText(cmdNode, "node");
|
||||
path = ParText(cmdNode, "node", nPar, "");
|
||||
node = FindHdbNode(NULL, path, con);
|
||||
if (node == NULL) {
|
||||
SCPrintf(con, eError, "ERROR: %s not found", path);
|
||||
return 0;
|
||||
}
|
||||
SetHdbProperty(node,"geterror","Not read yet");
|
||||
interval = ParValue(cmdNode, "interval");
|
||||
prio = DevText2Prio(ParText(cmdNode, "prio"));
|
||||
action = ParText(cmdNode, "action");
|
||||
|
||||
SctAddPollNode(controller, node, interval, prio, action);
|
||||
interval = ParValue(cmdNode, "interval", nPar, 5);
|
||||
prioText = ParText(cmdNode, "prio", nPar, "read");
|
||||
prio = DevText2Prio(prioText);
|
||||
if (prio == NullPRIO) {
|
||||
SCPrintf(con,eError, "ERROR: unknown priority: %s", prioText);
|
||||
return 0;
|
||||
}
|
||||
action = ParText(cmdNode, "action", nPar, "read");
|
||||
|
||||
if (SctAddPollNode(controller, node, interval, prio, action) > 0) {
|
||||
SCPrintf(con, eValue,
|
||||
"%s poll on %s changed to %g sec, %s prio",
|
||||
action, path, interval, prioText);
|
||||
} else {
|
||||
SCPrintf(con, eValue,
|
||||
"%s poll registered on %s (%g sec, %s prio)",
|
||||
action, path, interval, prioText);
|
||||
}
|
||||
sct->base->node = node;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int SctUnpollCmd(pSICSOBJ ccmd, SConnection *con,
|
||||
Hdb *cmdNode, Hdb *par[], int nPar) {
|
||||
SctController *controller;
|
||||
double interval;
|
||||
char *path;
|
||||
DevPrio prio;
|
||||
char *prioText;
|
||||
SctData data;
|
||||
|
||||
if(nPar < 1){
|
||||
SCPrintf(con,eError,
|
||||
"ERROR: should be: %s poll <node> (<action>)",
|
||||
ccmd->objectNode->name);
|
||||
return 0;
|
||||
}
|
||||
controller = ccmd->pPrivate;
|
||||
path = ParText(cmdNode, "node", nPar, "");
|
||||
data.node = FindHdbNode(NULL, path, con);
|
||||
if (data.node == NULL) {
|
||||
SCPrintf(con, eError, "ERROR: %s not found", path);
|
||||
return 0;
|
||||
}
|
||||
data.name = ParText(cmdNode, "action", nPar, "read");
|
||||
if (DevUnschedule(controller->devser, &data, SctActionHandler, SctMatch) == 0) {
|
||||
SCPrintf(con, eValue,
|
||||
"%s poll not found on %s", data.name, path);
|
||||
} else {
|
||||
SCSendOK(con);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -575,7 +653,7 @@ static int SctConnectCmd(pSICSOBJ ccmd, SConnection *con,
|
||||
return 0;
|
||||
}
|
||||
controller = ccmd->pPrivate;
|
||||
path = ParText(cmdNode, "node");
|
||||
path = ParText(cmdNode, "node", nPar, "");
|
||||
node = FindHdbNode(NULL, path, con);
|
||||
if (node == NULL) {
|
||||
SCPrintf(con, eError, "ERROR: %s not found", path);
|
||||
@@ -601,7 +679,7 @@ int SctAddWriteNode(SctController *controller, Hdb *node) {
|
||||
AppendHipadabaCallback(node, cb);
|
||||
}
|
||||
|
||||
actionCallback.name = strdup("write");
|
||||
actionCallback.name = "write"; /* local, so no strdup here */
|
||||
data = FindHdbCallbackData(node, &actionCallback);
|
||||
if (data != NULL) {
|
||||
return 0;
|
||||
@@ -610,11 +688,10 @@ int SctAddWriteNode(SctController *controller, Hdb *node) {
|
||||
assert(data);
|
||||
data->controller = controller;
|
||||
data->node = node;
|
||||
data->writable = 1;
|
||||
data->conCtx = NULL;
|
||||
data->name = strdup("write");
|
||||
|
||||
cb = MakeHipadabaCallback(SctActionCallback, data, SctKillData);
|
||||
cb = MakeHipadabaCallback(SctActionCallback, data, SctKillCBData);
|
||||
assert(cb);
|
||||
data->node = node;
|
||||
AppendHipadabaCallback(node, cb);
|
||||
@@ -635,7 +712,7 @@ static int SctWriteCmd(pSICSOBJ ccmd, SConnection *con,
|
||||
return 0;
|
||||
}
|
||||
controller = ccmd->pPrivate;
|
||||
path = ParText(cmdNode, "node");
|
||||
path = ParText(cmdNode, "node", nPar, "");
|
||||
node = FindHdbNode(NULL, path, con);
|
||||
if (node == NULL) {
|
||||
SCPrintf(con, eError, "ERROR: %s not found", path);
|
||||
@@ -647,12 +724,13 @@ static int SctWriteCmd(pSICSOBJ ccmd, SConnection *con,
|
||||
return 0;
|
||||
}
|
||||
|
||||
SCSendOK(con);
|
||||
sct->base->node = node;
|
||||
return 1;
|
||||
}
|
||||
|
||||
SctData *SctQueueNode(SctController *controller, Hdb *node,
|
||||
DevPrio prio, char *action) {
|
||||
void SctQueueNode(SctController *controller, Hdb *node,
|
||||
DevPrio prio, char *action, SConnection *con) {
|
||||
SctData *data;
|
||||
hdbCallback *cb;
|
||||
|
||||
@@ -666,13 +744,15 @@ SctData *SctQueueNode(SctController *controller, Hdb *node,
|
||||
assert(data);
|
||||
data->controller = controller;
|
||||
data->node = node;
|
||||
data->writable = 0;
|
||||
data->name = strdup(action);
|
||||
data->conCtx = NULL;
|
||||
|
||||
DevQueue(data->controller->devser, data, prio,
|
||||
SctWriteHandler, SctMatch, SctKillData);
|
||||
return data;
|
||||
if (con != NULL) {
|
||||
data->conCtx = SCSave(con, NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int SctQueueCmd(pSICSOBJ ccmd, SConnection *con,
|
||||
@@ -684,24 +764,30 @@ static int SctQueueCmd(pSICSOBJ ccmd, SConnection *con,
|
||||
char *action;
|
||||
DevPrio prio;
|
||||
SctData *data;
|
||||
char *prioText;
|
||||
|
||||
if(nPar < 2){
|
||||
SCPrintf(con,eError, "ERROR: should be: %s queue <node> <prio> <action>",
|
||||
SCPrintf(con,eError,
|
||||
"ERROR: should be: %s queue <node> <prio> <action>",
|
||||
ccmd->objectNode->name);
|
||||
return 0;
|
||||
}
|
||||
controller = ccmd->pPrivate;
|
||||
path = ParText(cmdNode, "node");
|
||||
path = ParText(cmdNode, "node", nPar, "");
|
||||
node = FindHdbNode(NULL, path, con);
|
||||
if (node == NULL) {
|
||||
SCPrintf(con, eError, "ERROR: %s not found", path);
|
||||
return 0;
|
||||
}
|
||||
prio = DevText2Prio(ParText(cmdNode, "prio"));
|
||||
action = ParText(cmdNode, "action");
|
||||
prioText = ParText(cmdNode, "prio", nPar, "write");
|
||||
prio = DevText2Prio(prioText);
|
||||
if (prio == NullPRIO) {
|
||||
SCPrintf(con,eError, "ERROR: unknown priority: %s", prioText);
|
||||
return 0;
|
||||
}
|
||||
action = ParText(cmdNode, "action", nPar, "write");
|
||||
|
||||
data = SctQueueNode(controller, node, prio, action);
|
||||
data->conCtx = SCSave(con, NULL);
|
||||
SctQueueNode(controller, node, prio, action, con);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -765,7 +851,7 @@ static int SctTransactCmd(pSICSOBJ ccmd, SConnection *con,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int SctQueueComCmd(pSICSOBJ ccmd, SConnection *con,
|
||||
static int SctSendCmd(pSICSOBJ ccmd, SConnection *con,
|
||||
Hdb *cmdNode, Hdb *par[], int nPar) {
|
||||
pSctTransact st = NULL;
|
||||
SctController *c;
|
||||
@@ -774,7 +860,7 @@ static int SctQueueComCmd(pSICSOBJ ccmd, SConnection *con,
|
||||
|
||||
st = calloc(sizeof(SctTransact),1);
|
||||
if(st == NULL){
|
||||
SCWrite(con,"ERROR: out of memory in SctTransactCommand", eError);
|
||||
SCWrite(con,"ERROR: out of memory in SctSendCmd", eError);
|
||||
return 0;
|
||||
}
|
||||
st->con = con;
|
||||
@@ -812,10 +898,17 @@ static hdbCallbackReturn SctDebugCallback(Hdb *node, void *userData,
|
||||
|
||||
static void SctKillController(void *c) {
|
||||
SctController *controller = c;
|
||||
SConnection *con;
|
||||
|
||||
CleanStack(controller->node);
|
||||
RemoveSICSInternalCallback(controller);
|
||||
/* devser is killed by task function */
|
||||
if (controller->conn) {
|
||||
con = SCLoad(controller->conn);
|
||||
SCDeleteConnection(con);
|
||||
SCStoreFree(controller->conn);
|
||||
}
|
||||
DevKill(controller->devser);
|
||||
free(controller);
|
||||
}
|
||||
|
||||
static int SctMakeController(SConnection *con, SicsInterp *sics,
|
||||
@@ -864,6 +957,11 @@ static int SctMakeController(SConnection *con, SicsInterp *sics,
|
||||
AddSICSHdbPar(cmd, "prio", usMugger, MakeHdbText("read"));
|
||||
AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("read"));
|
||||
|
||||
cmd = AddSICSHdbPar(controller->node,
|
||||
"unpoll", usMugger, MakeSICSFunc(SctUnpollCmd));
|
||||
AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText(""));
|
||||
AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("read"));
|
||||
|
||||
cmd = AddSICSHdbPar(controller->node,
|
||||
"connect", usMugger, MakeSICSFunc(SctConnectCmd));
|
||||
AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText(""));
|
||||
@@ -884,11 +982,11 @@ static int SctMakeController(SConnection *con, SicsInterp *sics,
|
||||
AddSICSHdbPar(cmd, "data", usMugger, MakeHdbText(""));
|
||||
|
||||
cmd = AddSICSHdbPar(controller->node,
|
||||
"queuecom", usMugger, MakeSICSFunc(SctQueueComCmd));
|
||||
"send", usMugger, MakeSICSFunc(SctSendCmd));
|
||||
AddSICSHdbPar(cmd, "data", usMugger, MakeHdbText(""));
|
||||
|
||||
|
||||
par = AddSICSHdbPar(controller->node, "debug", usUser, MakeHdbInt(0));
|
||||
par = AddSICSHdbPar(controller->node, "debug", usUser, MakeHdbInt(-1));
|
||||
|
||||
cb = MakeHipadabaCallback(SctDebugCallback, controller, NULL);
|
||||
if (cb) AppendHipadabaCallback(par, cb);
|
||||
@@ -918,10 +1016,6 @@ void SctKill(void *object) {
|
||||
sct = NULL;
|
||||
}
|
||||
|
||||
/* from sctdriveadapter.c */
|
||||
int SctMakeDriveAdapter(SConnection *pCon, SicsInterp *pSics, void *object,
|
||||
int argc, char *argv[]);
|
||||
|
||||
void SctInit(void) {
|
||||
if (sct) return;
|
||||
sct = calloc(1, sizeof(*sct));
|
||||
@@ -931,5 +1025,4 @@ void SctInit(void) {
|
||||
sct->base = sct->nodes;
|
||||
AddCommand(pServ->pSics, "sct", SctCommand, SctKill, sct);
|
||||
AddCmd("makesctcontroller", SctMakeController);
|
||||
AddCmd("makesctdrive", SctMakeDriveAdapter);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user