Files
sics/scriptcontext.c
Ferdi Franceschini e36e9f1146 conman.c
Reduce log noise by setting iout = eInternal for macros.

servlog.c
Fixed timestamp in logfiles to get hours.

hmm_configuration_common_1.tcl
Added ML's mods to wombat config: ie BAT and FAT TABLE attributes and elements for multi-period acquisition and histo-streaming.
Fixed "failed lsearch" bug. It's more robust to test for a non-successful lsearch instead of a failed lsearch.

nxscripts_common_1.tcl
SICS-297 Fixed Saving data series in a scratch file overwrites earlier entries.

instdict_specification.tcl
Added "scobj" kind and "sct_indexed_motor" sics object type for script context controllers and and objects.

hipadaba_configuration_common.tcl
Added sct_indexed_motor sics obj type to ::hdb::sobjadd and scobj kind to ::hdb::add_node

sct_positmotor_common.tcl
Update the index SICS variable when updating the current index value to make sure that the position is saved in the data file.
You must now provide the hdb node_name when creating the sct posit motor.
mk_sct_positmotor now sets the "param" and "long_name" attributes on the posit motor object

util/utility.tcl
Added ::utility::set_sct_indexed_motor_attributes to set SICS object attributes required for generating hdb info for an SCT_POSIT_MOTOR

nxscript.c
Merge the ansto mod to putslab (rev1.7) which adds support for saving unbuffered data from the histmem.

sicshipadaba.c
This incorporates the patch made to CommandSetCallback in rev1.10 so it can just be copied as is (ie no merge required).
WARNING: There are changes to ListHdbNode to handle record separators which may affect us.
Disabled sending hdb command start and stop messages because they break gumtree

sicshdbfactory.c
Disabled sending hdb command start and stop messages because they break gumtree

hipadaba_configuration_common.tcl R2.4DEV
The sct_posit_motor case of ::hdb::sobjadd is only needed to call add_node with kind=scobj.

nxscripts_common_1.tcl R2.4DEV
Added ::nexus::scobj::sdsinfo
_gen_nxdict now skips nodes with data_type == "none"

new util/script_context_util.tcl R2.4DEV
Adds ::scobj::hinitprops command to initialise the hdb properties for script context object nodes.

sct_positmotor_common.tcl R2.4DEV
Use ::scobj::hinitprops utility command to initialise hdb properties on script context object parameter nodes.

dynstring.c
DynStringReplace should memcopy '\0', otherwise it can get the wrong length for iTextLen.
Added DynStringReplaceWithLen to allow initialising a dynstring with char arrays which contain null chars and
other non-ascii chars.  Useful for read and write buffers in script context.

ascon.c
AsconRead return NULL for noResponse and AsconFailed otherwise the "result" node gets set with a spurious empty value.

scriptcontext.c
SctActionHandler only set  the "result" node if there really is a reply.

sicsobj.c
Update from M.K.

site_ansto.c
Added galil and ordela hvps protocol handlers for scriptcontext.

motor_dmc2280.c
Allow home parameter to be outside of limits (for KOWARI)

hardsup/makefile
Added ordela HVPS protocol handler

hardsup/sct_orhvpsprot.c
New ordela HVPS protocol handler.  Retries on NAKs and re-orders pot channels (ie toggles lower two bits).

hardsup/sct_velselprot.c
Start velocity selector protocol handler.

hardsup/sct_galilprot.c
Completed galil protocol handler.

hipadaba_configuration_common.tcl
Add new style SICS objects to hdb tree.

instdict_specification.tcl
Added scobj to kind list and sct_motor to sics object list. (and some housekeeping)

hmm_configuration_common_1.tcl
Added ratemaps to simulation.  Fixe BAT_TABLE and added PERIOD_INDICES as per Mark Lesha's mods for multi-period acquisition.
ratemaps now return float.

sct_postimotor_common.tcl
Now setting properties on the posit motor object so that it can be automatically added to the hdb tree.

hrpd/config/motors/motor_configuration.tcl
Fixed simulated msd motor so that it's handle properly in the hdb layer.

sans/config/hmm/detector_ordela.tcl
Updated the ordela calibration script to use the new sct_orhvpsprop.c script context controller.

quokka_configuration.tcl
Deleted lines which set the hdb properties for script context posit motors.  This is now handled automatically as for other SICS objects.

utility.tcl
setpos now replaces the motor setpos subcommand.
Added functions to set script context object attributes and sct_posit motor attributes.
Created hparPath and hsibPath convenience commands for new-style SICS objects.

script_context_util.tcl
NEW! Adds hinitprops function to initialise the hdb properties for a script context object

r2758 | ffr | 2008-12-12 17:53:53 +1100 (Fri, 12 Dec 2008) | 113 lines
2012-11-15 16:56:43 +11:00

1038 lines
26 KiB
C

#include <strings.h>
#include <tcl.h>
#include <time.h>
#include <math.h>
#include "sics.h"
#include "sicsobj.h"
#include "splitter.h"
#include "initializer.h"
#include "commandlog.h"
#include "hipadaba.h"
#include "sicshipadaba.h"
#include "dynstring.h"
#include "devser.h"
#include "ascon.h"
#include "macro.h"
#include "scriptcontext.h"
#define MAX_HDB_PATH 1024
typedef struct ContextItem {
struct ContextItem *next;
Hdb *node;
Hdb *controllerNode;
} ContextItem;
typedef struct ScriptContext {
ObjectDescriptor *desc;
ContextItem *nodes;
ContextItem *trash;
} ScriptContext;
struct SctController {
DevSer *devser;
Hdb *node; /* the controller node */
SCStore *conn;
int verbose;
};
/* action data and write callback data */
typedef struct SctData {
char *name;
SctController *controller;
SCStore *conCtx;
int answered;
Hdb *node;
} SctData;
static ScriptContext *sct = NULL;
static SCStore *currentCon = NULL;
static struct {
char *name;
} actionCallback;
static char *mainCallback = "main callback";
void PushContext(Hdb *node, Hdb *controllerNode) {
ContextItem *new;
if (sct->trash == NULL) {
new = calloc(1, sizeof(*new));
} else {
new = sct->trash;
sct->trash = sct->trash->next;
}
new->next = sct->nodes;
sct->nodes = new;
new->node = node;
new->controllerNode = controllerNode;
}
void PopContext(void) {
ContextItem *c;
c = sct->nodes;
assert(c);
sct->nodes = c->next;
c->next = sct->trash;
sct->trash = c;
}
void CleanStack(Hdb *node) {
ContextItem *s;
/* clean context from killed nodes */
for (s = sct->nodes; s != NULL; s = s->next) {
if (s->node == node) {
s->node = NULL;
}
if (s->controllerNode == node) {
s->controllerNode = NULL;
}
}
}
static void SetProp(Hdb *node, Hdb *cNode, char *key, char *value) {
char *val;
if (node == NULL) {
if (cNode == NULL) return;
node = cNode;
} else {
val = GetHdbProp(node, key);
if (val == NULL && cNode != NULL) {
val = GetHdbProp(cNode, key);
if (val != NULL) {
node = cNode;
}
}
}
if (value == NULL) {
if (GetHdbProperty(node, key, NULL, 0) > 0) {
SetHdbProperty(node, key, "");
}
} else {
SetHdbProperty(node, key, value);
}
}
static char *GetProp(Hdb *node, Hdb *cNode, char *key) {
char *val;
if (node != NULL) {
val = GetHdbProp(node, key);
if (val != NULL) return val;
}
if (cNode != NULL) {
val = GetHdbProp(cNode, key);
}
return val;
}
/*
* This is the actual sct command available in scripts.
*/
int SctCommand(SConnection *con, SicsInterp *sics, void *object,
int argc, char *argv[]) {
static char value[1024];
char *val;
char error[512];
Hdb *node = NULL;
Hdb *cNode = NULL;
hdbValue v;
double dtime;
assert(sct == object);
if (sct->nodes != NULL) {
node = sct->nodes->node;
cNode = sct->nodes->controllerNode;
}
if (node == NULL && cNode == NULL) {
SCPrintf(con, eError, "ERROR: %s may be called only in proper context",
argv[0]);
return 0;
}
if (argc <= 1) {
GetHdbPath(node, value, sizeof value);
SCWrite(con, value, eValue);
return 1;
}
/*
* update command
*/
if(strcmp(argv[1],"update") == 0){
cloneHdbValue(&node->value, &v);
Arg2Text(argc-2, argv+2, value, sizeof value);
if(!readHdbValue(&v, value, error, 512)){
SCWrite(con, error, eError);
return 0;
}
UpdateHipadabaPar(node,v,con);
SetHdbProperty(node,"geterror", NULL);
return 1;
}
/*
* print
*/
if(strcmp(argv[1],"print") == 0){
Arg2Text(argc-2, argv+2, value, sizeof value);
SCWrite(con,value,eWarning);
return 1;
}
/*
* time stamping
*/
if(strcmp(argv[1],"utime") == 0){
if(argc < 3){
SCWrite(con,"ERROR: need property to write time stamp too",
eError);
return 0;
}
dtime = DoubleTime();
snprintf(value,1024,"%.3f",dtime);
SetHdbProperty(node,argv[2], value);
return 1;
}
/*
* property handling
*/
if (argc == 2) { /* get case */
val = GetProp(node, cNode, argv[1]);
if (val == NULL) {
SCPrintf(con, eError, "ERROR: %s %s not found", argv[0], argv[1]);
return 0;
}
SCWrite(con, val, eValue);
} else { /* set case */
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;
}
int SctCallInContext(SConnection *con, char *script, Hdb *node,
SctController *controller, char **resPtr) {
Tcl_Interp *pTcl = InterpGetTcl(pServ->pSics);
int ret, l;
char *result = NULL;
int iRet = 1;
int verbose = controller->verbose;
PushContext(node, controller->node);
if (verbose) {
SCPrintf(con, eInError, "\nscript: %s\n", script);
}
MacroPush(con);
l = strlen(script);
ret = Tcl_EvalEx(pTcl, script, l, 0);
result = (char *)Tcl_GetStringResult(pTcl);
if (ret != TCL_OK && result[0]!='\0') {
if (verbose) {
SCPrintf(con, eInError, "\nerror: %s\n", result);
}
iRet = 0;
}
*resPtr = result;
MacroPop();
PopContext();
return iRet;
}
static int SctMatch(void *data1, void *data2) {
SctData *a = data1;
SctData *b = data2;
return a->node == b->node && strcasecmp(a->name, b->name) == 0;
}
static char *SctActionHandler(void *actionData, char *lastReply) {
SctData *data = actionData;
Hdb *node = data->node;
SctController *controller = data->controller;
char *state;
char *result;
char *script;
char *send = NULL;
int i;
SConnection *con;
char timeKey[50], timeVal[50];
if (currentCon) {
con = SCStorePush(currentCon);
} else {
con = SCStorePush(controller->conn);
}
if (lastReply != NULL) {
SetProp(node, controller->node, "result", lastReply);
}
if (controller->verbose && lastReply != NULL && *lastReply != '\0') {
SCPrintf(con, eWarning, "reply : %s", lastReply);
}
state = GetProp(node, controller->node, "state");
if (state == NULL || strcasecmp(state, "idle") == 0) {
state = data->name;
SetProp(node, controller->node, "state", state);
}
for (i = 0; i < 10; i++) {
SetProp(node, controller->node, "send", NULL);
script = GetProp(node, controller->node, state);
if (script == NULL) script = state;
if (! SctCallInContext(con, script, node, data->controller, &result)) {
SCPrintf(con, eError, "ERROR: %s", result);
goto finish;
}
state = result;
if (strcasecmp(state, "idle") == 0) {
if (currentCon && ! data->answered) {
SCWrite(con, "o.k.", eValue);
}
if(strcmp(data->name,"write") == 0){
SetHdbProperty(data->node,"writestatus","commandsent");
}
snprintf(timeKey,50,"%s_time",data->name);
snprintf(timeVal,50,"%.3f", DoubleTime());
SetHdbProperty(data->node,timeKey,timeVal);
goto finish;
}
SetProp(node, controller->node, "state", state);
send = GetProp(node, controller->node, "send");
if (send != NULL && send[0] != '\0') {
if (controller->verbose) {
SCPrintf(con, eWarning, "send : %s", send);
}
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");
if (currentCon) {
SCStorePop(currentCon);
} else {
SCStorePop(controller->conn);
}
if (data->conCtx != NULL) {
SCStoreFree(data->conCtx);
data->conCtx = NULL;
}
return send;
}
static char *SctWriteHandler(void *actionData, char *lastReply) {
SctData *data = actionData;
SCStore *old;
char *result;
old = currentCon;
currentCon = data->conCtx;
result = SctActionHandler(data, lastReply);
currentCon = old;
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;
hdbDataSearch *dsm;
hdbDataMessage *mm;
hdbPtrMessage *pm;
hdbMessage *km;
ContextItem *s;
SConnection *con;
char *geterror;
pm = GetKillPtrMessage(msg);
if (pm != NULL) {
if (controller == pm->pPtr) {
return hdbKill;
}
return hdbContinue;
}
dsm = GetHdbDataSearchMessage(msg);
if (dsm != NULL) {
if (dsm->testPtr == controller) {
dsm->result = controller;
return hdbAbort;
}
return hdbContinue;
}
km = GetHdbKillNodeMessage(msg);
if (km != NULL) {
/* unschedule all actions related to this node */
DevUnschedule(controller->devser, node, SctActionHandler, SctMatchNode);
CleanStack(node);
return hdbContinue;
}
mm = GetHdbGetMessage(msg);
if (mm != NULL) {
con = mm->callData;
geterror = GetHdbProp(node, "geterror");
if (geterror != NULL) {
SCPrintf(con, eError, "ERROR: %s", geterror);
return hdbAbort;
}
return hdbContinue;
}
return hdbContinue;
}
static hdbCallbackReturn SctActionCallback(Hdb *node, void *userData,
hdbMessage *msg) {
hdbDataSearch *dsm;
hdbDataMessage *mm;
hdbPtrMessage *pm;
hdbMessage *km;
SctData *data = userData;
Hdb *target;
char *script;
int l;
int iRet;
pDynString text;
DevPrio prio;
char *writeprio;
char *error;
SConnection *con;
SConnection *con2;
char path[MAX_HDB_PATH];
pm = GetKillPtrMessage(msg);
if (pm != NULL) {
if (data->controller == pm->pPtr) {
return hdbKill;
}
return hdbContinue;
}
dsm = GetHdbDataSearchMessage(msg);
if (dsm != NULL) {
if (dsm->testPtr == &actionCallback) {
if (strcasecmp(data->name, actionCallback.name) == 0) {
dsm->result = data;
}
return hdbAbort;
}
return hdbContinue;
}
mm = GetHdbSetMessage(msg);
if (mm != NULL) {
con = mm->callData;
/* set target value */
text = formatValue(*(mm->v), node);
SetHdbProperty(node, "target", GetCharArray(text));
/* call check script, if available */
script = GetProp(node, data->controller->node, "check");
if (script != NULL) {
if (SctCallInContext(con, script, node, data->controller, &error) == 0) {
SCPrintf(con, eError, "ERROR: %s", error);
SetHdbProperty(node,"target", NULL);
return hdbAbort;
}
}
/* enqueue write action */
writeprio = GetProp(node, data->controller->node, "writeprio");
if (writeprio != NULL) {
prio = DevText2Prio(writeprio);
if (prio == NullPRIO) {
SCPrintf(con, eError, "ERROR: unknown priority: %s", writeprio);
prio = WritePRIO;
}
} else {
prio = WritePRIO;
}
if (data->conCtx != NULL) {
con2 = SCStorePush(data->conCtx);
GetHdbPath(node, path, sizeof path);
SCPrintf(con2, eValue, "%s target changed to %s before completion",
path, GetCharArray(text));
SCStorePop(data->conCtx);
}
DeleteDynString(text);
data->conCtx = SCSave(con, data->conCtx);
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;
}
mm = GetHdbUpdateMessage(msg);
if (mm != NULL) {
if (currentCon) { /* update called from a write action */
data->answered = 1;
GetHdbPath(node, path, sizeof path);
con = SCStorePush(currentCon);
text = formatValue(*(mm->v), node);
SCPrintf(con, eStatus, "%s = %s", path,
GetCharArray(text));
DeleteDynString(text);
SCStorePop(currentCon);
}
return hdbContinue;
}
return hdbContinue;
}
static char *ParText(Hdb *cmdNode, char *name,
int nPar, char *defaultValue) {
Hdb *par;
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 defaultValue;
}
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);
}
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;
if (! FindHdbCallbackData(node, controller)) {
cb = MakeHipadabaCallback(SctMainCallback, controller, NULL);
assert(cb);
AppendHipadabaCallback(node, cb);
SetHdbProperty(node,"geterror","Not read yet");
}
data = calloc(1, sizeof(*data));
assert(data);
data->controller = controller;
data->node = node;
data->conCtx = NULL;
data->name = strdup(action);
return DevSchedule(controller->devser, data, prio, interval,
SctActionHandler, SctMatch, SctKillData);
}
static int SctPollCmd(pSICSOBJ ccmd, SConnection *con,
Hdb *cmdNode, Hdb *par[], int nPar) {
Hdb *node;
SctController *controller;
double interval;
char *path;
DevPrio prio;
char *action;
char *prioText;
if(nPar < 1){
SCPrintf(con,eError,
"ERROR: should be: %s poll <node> (<interval> <prio> <action>)",
ccmd->objectNode->name);
return 0;
}
controller = ccmd->pPrivate;
path = ParText(cmdNode, "node", nPar, "");
node = FindHdbNode(NULL, path, con);
if (node == NULL) {
SCPrintf(con, eError, "ERROR: %s not found", path);
return 0;
}
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);
}
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;
}
static int SctConnectCmd(pSICSOBJ ccmd, SConnection *con,
Hdb *cmdNode, Hdb *par[], int nPar) {
Hdb *node;
SctController *controller;
char *path;
hdbCallback *cb;
if(nPar < 1){
SCPrintf(con,eError,
"ERROR: should be: %s connect <node> ",
ccmd->objectNode->name);
return 0;
}
controller = ccmd->pPrivate;
path = ParText(cmdNode, "node", nPar, "");
node = FindHdbNode(NULL, path, con);
if (node == NULL) {
SCPrintf(con, eError, "ERROR: %s not found", path);
return 0;
}
if (! FindHdbCallbackData(node, controller)) {
cb = MakeHipadabaCallback(SctMainCallback, controller, NULL);
assert(cb);
AppendHipadabaCallback(node, cb);
}
SCSendOK(con);
return 1;
}
int SctAddWriteNode(SctController *controller, Hdb *node) {
hdbCallback *cb;
SctData *data;
if (! FindHdbCallbackData(node, controller)) {
cb = MakeHipadabaCallback(SctMainCallback, controller, NULL);
assert(cb);
AppendHipadabaCallback(node, cb);
}
actionCallback.name = "write"; /* local, so no strdup here */
data = FindHdbCallbackData(node, &actionCallback);
if (data != NULL) {
return 0;
}
data = calloc(1, sizeof(*data));
assert(data);
data->controller = controller;
data->node = node;
data->conCtx = NULL;
data->name = strdup("write");
cb = MakeHipadabaCallback(SctActionCallback, data, SctKillCBData);
assert(cb);
data->node = node;
AppendHipadabaCallback(node, cb);
RemoveSetUpdateCallback(node);
return 1;
}
static int SctWriteCmd(pSICSOBJ ccmd, SConnection *con,
Hdb *cmdNode, Hdb *par[], int nPar) {
Hdb *node;
SctController *controller;
double interval;
char *path;
if(nPar < 1){
SCPrintf(con, eError, "ERROR: should be: %s write <node>",
ccmd->objectNode->name);
return 0;
}
controller = ccmd->pPrivate;
path = ParText(cmdNode, "node", nPar, "");
node = FindHdbNode(NULL, path, con);
if (node == NULL) {
SCPrintf(con, eError, "ERROR: %s not found", path);
return 0;
}
if (SctAddWriteNode(controller, node) == 0) {
SCPrintf(con, eError,
"ERROR: %s has already a write action", path);
return 0;
}
SCSendOK(con);
return 1;
}
void SctQueueNode(SctController *controller, Hdb *node,
DevPrio prio, char *action, SConnection *con) {
SctData *data;
hdbCallback *cb;
if (! FindHdbCallbackData(node, controller)) {
cb = MakeHipadabaCallback(SctMainCallback, controller, NULL);
assert(cb);
AppendHipadabaCallback(node, cb);
}
data = calloc(1, sizeof(*data));
assert(data);
data->controller = controller;
data->node = node;
data->name = strdup(action);
data->conCtx = NULL;
DevQueue(data->controller->devser, data, prio,
SctWriteHandler, SctMatch, SctKillData);
if (con != NULL) {
data->conCtx = SCSave(con, NULL);
}
return;
}
static int SctQueueCmd(pSICSOBJ ccmd, SConnection *con,
Hdb *cmdNode, Hdb *par[], int nPar) {
Hdb *node;
SctController *controller;
double interval;
char *path;
char *action;
DevPrio prio;
SctData *data;
char *prioText;
if(nPar < 2){
SCPrintf(con,eError,
"ERROR: should be: %s queue <node> <prio> <action>",
ccmd->objectNode->name);
return 0;
}
controller = ccmd->pPrivate;
path = ParText(cmdNode, "node", nPar, "");
node = FindHdbNode(NULL, path, con);
if (node == NULL) {
SCPrintf(con, eError, "ERROR: %s not found", path);
return 0;
}
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");
SctQueueNode(controller, node, prio, action, con);
return 1;
}
typedef struct SctTransact {
char *command;
int sent;
SConnection *con;
}SctTransact, *pSctTransact;
static void KillSctTransact(void *data){
pSctTransact self = (pSctTransact)data;
if(self == NULL){
return;
}
if(self->command){
free(self->command);
}
free(self);
}
static char *TransactionHandler(void *actionData, char *lastReply){
pSctTransact st = (pSctTransact)actionData;
if(st->sent == 0){
st->sent = 1;
return st->command;
} else {
st->sent = 2;
SCWrite(st->con,lastReply, eValue);
return NULL;
}
}
static int SctTransactMatch(void *d1, void *d2){
return d1 == d2;
}
static int SctTransactCmd(pSICSOBJ ccmd, SConnection *con,
Hdb *cmdNode, Hdb *par[], int nPar) {
pSctTransact st = NULL;
SctController *c;
c = (SctController *)ccmd->pPrivate;
st = calloc(sizeof(SctTransact),1);
if(st == NULL){
SCWrite(con,"ERROR: out of memory in SctTransactCommand", eError);
return 0;
}
st->con = con;
st->command = strdup(par[0]->value.v.text);
DevQueue(c->devser, st, WritePRIO,
TransactionHandler, SctTransactMatch, NULL);
while(st->sent != 2){
TaskYield(pServ->pTasker);
if(SCGetInterrupt(con) != eContinue){
break;
}
}
KillSctTransact(st);
return 1;
}
static int SctSendCmd(pSICSOBJ ccmd, SConnection *con,
Hdb *cmdNode, Hdb *par[], int nPar) {
pSctTransact st = NULL;
SctController *c;
c = (SctController *)ccmd->pPrivate;
st = calloc(sizeof(SctTransact),1);
if(st == NULL){
SCWrite(con,"ERROR: out of memory in SctSendCmd", eError);
return 0;
}
st->con = con;
st->command = strdup(par[0]->value.v.text);
DevQueue(c->devser, st, WritePRIO,
TransactionHandler, SctTransactMatch, KillSctTransact);
return 1;
}
static hdbCallbackReturn SctDebugCallback(Hdb *node, void *userData,
hdbMessage *msg) {
hdbDataMessage *mm;
SctController *controller = userData;
SConnection *con;
int i;
mm = GetHdbSetMessage(msg);
if (mm != NULL) {
i = mm->v->v.intValue;
if (i < 0) {
controller->verbose = 0;
DevDebugMode(controller->devser, -1);
} else if (i == 0) {
controller->verbose = 1;
DevDebugMode(controller->devser, -1);
} else {
controller->verbose = 1;
DevDebugMode(controller->devser, i);
}
}
return hdbContinue;
}
static void SctKillController(void *c) {
SctController *controller = c;
SConnection *con;
CleanStack(controller->node);
RemoveSICSInternalCallback(controller);
if (controller->conn) {
con = SCLoad(controller->conn);
SCDeleteConnection(con);
SCStoreFree(controller->conn);
}
DevKill(controller->devser);
free(controller);
}
static int SctMakeController(SConnection *con, SicsInterp *sics,
void *object, int argc, char *argv[]) {
SICSOBJ *ccmd;
Hdb *parent, *par, *cmd;
char *nodeName;
hdbCallback *cb;
SctController *controller;
if (argc < 2) {
SCPrintf(con, eError,
"ERROR: should be %s <path> <protocol args> ...",
argv[0]);
return 0;
}
parent = FindHdbParent(NULL, argv[1], &nodeName, con);
if (parent == NULL) return 0; /* error message already written */
controller = calloc(1, sizeof(*controller));
assert(controller);
controller->verbose = 0;
ccmd = MakeSICSOBJv(nodeName, "SctController", HIPNONE, usSpy);
controller->node = ccmd->objectNode;
controller->conn = SCSave(SCCreateDummyConnection(pServ->pSics), NULL);
assert(ccmd);
assert(controller->node->mama == NULL);
ccmd->pPrivate = controller;
ccmd->KillPrivate = SctKillController;
AddHipadabaChild(parent, controller->node, con);
controller->devser = DevMake(con, argc - 2, argv + 2);
if (!controller->devser) return 0;
AddCommand(pServ->pSics, nodeName, InvokeSICSOBJ, KillSICSOBJ, ccmd);
SetDescriptorKey(ccmd->pDes, "creationCommand", "0");
cmd = AddSICSHdbPar(controller->node,
"poll", usMugger, MakeSICSFunc(SctPollCmd));
AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText(""));
AddSICSHdbPar(cmd, "interval", usMugger, MakeHdbFloat(5.0));
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(""));
cmd = AddSICSHdbPar(controller->node,
"write", usMugger, MakeSICSFunc(SctWriteCmd));
AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText(""));
cmd = AddSICSHdbPar(controller->node,
"queue", usMugger, MakeSICSFunc(SctQueueCmd));
AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText(""));
AddSICSHdbPar(cmd, "prio", usMugger, MakeHdbText("write"));
AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("write"));
cmd = AddSICSHdbPar(controller->node,
"transact", usMugger, MakeSICSFunc(SctTransactCmd));
AddSICSHdbPar(cmd, "data", usMugger, MakeHdbText(""));
cmd = AddSICSHdbPar(controller->node,
"send", usMugger, MakeSICSFunc(SctSendCmd));
AddSICSHdbPar(cmd, "data", usMugger, MakeHdbText(""));
par = AddSICSHdbPar(controller->node, "debug", usUser, MakeHdbInt(-1));
cb = MakeHipadabaCallback(SctDebugCallback, controller, NULL);
if (cb) AppendHipadabaCallback(par, cb);
return 1;
}
void SctKill(void *object) {
assert(sct == object);
ContextItem *p, *q;
for (p = sct->nodes; p != NULL; p = q) {
q = p->next;
free(p);
}
for (p = sct->trash; p != NULL; p = q) {
q = p->next;
free(p);
}
if (sct->desc != NULL) {
DeleteDescriptor(sct->desc);
}
free(sct);
sct = NULL;
}
void SctInit(void) {
if (sct) return;
sct = calloc(1, sizeof(*sct));
assert(sct);
sct->desc = CreateDescriptor("ScriptContext");
AddCommand(pServ->pSics, "sct", SctCommand, SctKill, sct);
AddCmd("makesctcontroller", SctMakeController);
}
int SctVerbose(SctController *c){
return c->verbose;
}