- 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:
zolliker
2008-06-13 11:22:13 +00:00
parent d75eee789b
commit 9e7a6cfd74
7 changed files with 366 additions and 150 deletions

View File

@ -652,7 +652,7 @@ static int checkInterrupt(pCheckContext pCheck, int targetStatus){
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
static int initializeCheck(pCheckContext pCheck, pDevEntry pDev){ static int initializeCheck(pCheckContext pCheck, pDevEntry pDev){
int eCode; int eCode = HWFault;
SCPushContext(pCheck->self->pOwner, SCPushContext(pCheck->self->pOwner,
pDev->comCon.transID, pDev->comCon.deviceID); pDev->comCon.transID, pDev->comCon.deviceID);

View File

@ -26,8 +26,8 @@ struct DevSer {
DevAction *actions; /* the action queue */ DevAction *actions; /* the action queue */
SchedHeader *headers; SchedHeader *headers;
ErrMsg *errmsg; ErrMsg *errmsg;
int killMe;
int steps; int steps;
int stopTask;
}; };
static char *devPrio[NumberOfPRIO] = { static char *devPrio[NumberOfPRIO] = {
@ -59,10 +59,14 @@ static void DevFreeActionList(DevAction *actions) {
} }
} }
static void DevKillTask(void *devser) { static void DevKillTask(void *ds) {
if(devser != NULL){ DevSer *devser = ds;
DevKill(devser);
} if (devser->stopTask) {
free(devser);
} else {
devser->stopTask = 1;
}
} }
DevAction *DevNextAction(DevSer *devser) { DevAction *DevNextAction(DevSer *devser) {
@ -83,8 +87,12 @@ DevAction *DevNextAction(DevSer *devser) {
if (header->followingAction == NULL) { if (header->followingAction == NULL) {
if (now >= header->timeDue) { if (now >= header->timeDue) {
header->followingAction = header->actions; header->followingAction = header->actions;
header->timeDue = (floor(now / header->interval) + 1) if (header->interval <= 0) {
* header->interval; header->timeDue = now;
} else {
header->timeDue = (floor(now / header->interval) + 1)
* header->interval;
}
} }
} }
if (header->followingAction != NULL) { if (header->followingAction != NULL) {
@ -110,7 +118,7 @@ int DevQueueTask(void *ds) {
char *replyData; char *replyData;
if (devser->steps == 0) return 1; if (devser->steps == 0) return 1;
if (devser->killMe) { if (devser->stopTask) {
return 0; return 0;
} }
action = devser->current; action = devser->current;
@ -128,9 +136,9 @@ int DevQueueTask(void *ds) {
devser->steps--; devser->steps--;
} }
if(status == AsconFailure){ if(status == AsconFailure){
replyData = devser->errmsg->text; replyData = devser->errmsg->text;
} else { } else {
replyData = AsconRead(devser->asyncConn); replyData = AsconRead(devser->asyncConn);
} }
sendData = action->hdl(action->data, replyData); sendData = action->hdl(action->data, replyData);
if (sendData != NULL) { if (sendData != NULL) {
@ -163,7 +171,7 @@ DevSer *DevMake(SConnection *con, int argc, char *argv[]) {
devser->killCurrent = 0; devser->killCurrent = 0;
devser->actions = NULL; devser->actions = NULL;
devser->headers = NULL; devser->headers = NULL;
devser->killMe = 0; devser->stopTask = 0;
devser->steps = -1; /* no debugging by default */ devser->steps = -1; /* no debugging by default */
TaskRegister(pServ->pTasker, DevQueueTask, NULL, DevKillTask, devser, 0); TaskRegister(pServ->pTasker, DevQueueTask, NULL, DevKillTask, devser, 0);
return devser; return devser;
@ -200,7 +208,11 @@ void DevKill(DevSer *devser) {
DevFreeActionList(victim->actions); DevFreeActionList(victim->actions);
free(victim); free(victim);
} }
devser->killMe = 1; if (devser->stopTask) {
free(devser);
} else {
devser->stopTask = 1;
}
} }
void DevQueue(DevSer *devser, void *actionData, DevPrio prio, void DevQueue(DevSer *devser, void *actionData, DevPrio prio,
@ -213,7 +225,7 @@ void DevQueue(DevSer *devser, void *actionData, DevPrio prio,
if (prio >= NumberOfPRIO) prio = NumberOfPRIO - 1; if (prio >= NumberOfPRIO) prio = NumberOfPRIO - 1;
ptr2Last = &devser->actions; ptr2Last = &devser->actions;
for (action = devser->actions; action != NULL && action->prio >= prio; action = action->next) { for (action = devser->actions; action != NULL && action->prio >= prio; action = action->next) {
if (matchFunc(actionData, action->data) && action->hdl == hdl) { if (action->hdl == hdl && matchFunc(actionData, action->data)) {
return; /* there is already an identic action */ return; /* there is already an identic action */
} }
ptr2Last = &action->next; ptr2Last = &action->next;
@ -234,11 +246,15 @@ int DevUnschedule(DevSer *devser, void *actionData,
for (header = devser->headers; header != NULL; header = header->next) { for (header = devser->headers; header != NULL; header = header->next) {
ptr2Last = &header->actions; ptr2Last = &header->actions;
for (action = header->actions; action != NULL; action = *ptr2Last) { for (action = header->actions; action != NULL; action = *ptr2Last) {
if (matchFunc(actionData, action->data) && action->hdl == hdl) { if (action->hdl == hdl && matchFunc(actionData, action->data)) {
if (action == header->followingAction) { if (action == header->followingAction) {
/* advance followingAction if equal*/ /* advance followingAction if equal*/
header->followingAction = action->next; header->followingAction = action->next;
} }
if (action == devser->current) {
devser->current = NULL;
devser->killCurrent = 0; /* should already be 0 */
}
cnt++; cnt++;
/* remove from list */ /* remove from list */
*ptr2Last = action->next; *ptr2Last = action->next;
@ -252,20 +268,21 @@ int DevUnschedule(DevSer *devser, void *actionData,
return cnt; return cnt;
} }
void DevSchedule(DevSer *devser, void *actionData, int DevSchedule(DevSer *devser, void *actionData,
DevPrio prio, double interval, DevPrio prio, double interval,
DevActionHandler hdl, DevActionMatch *matchFunc, DevActionHandler hdl, DevActionMatch *matchFunc,
DevKillActionData *killFunc) { DevKillActionData *killFunc) {
SchedHeader *header = NULL; SchedHeader *header = NULL;
SchedHeader **ptr2LastHeader = NULL; SchedHeader **ptr2LastHeader = NULL;
SchedHeader *newHeader; SchedHeader *newHeader;
DevAction *action = NULL; DevAction *action = NULL;
DevAction **ptr2Last = NULL; DevAction **ptr2Last = NULL;
DevAction *newAction; DevAction *newAction;
int ret;
if (prio <= NullPRIO) prio = NullPRIO + 1; if (prio <= NullPRIO) prio = NullPRIO + 1;
if (prio >= NumberOfPRIO) prio = NumberOfPRIO - 1; if (prio >= NumberOfPRIO) prio = NumberOfPRIO - 1;
DevUnschedule(devser, actionData, hdl, matchFunc); ret = DevUnschedule(devser, actionData, hdl, matchFunc);
newAction = DevNewAction(actionData, hdl, killFunc, prio); newAction = DevNewAction(actionData, hdl, killFunc, prio);
/* find matching header */ /* find matching header */
@ -279,7 +296,7 @@ void DevSchedule(DevSer *devser, void *actionData,
} }
*ptr2Last = newAction; *ptr2Last = newAction;
assert(newAction->next == NULL); assert(newAction->next == NULL);
return; return ret;
} else if (header->prio < newAction->prio || } else if (header->prio < newAction->prio ||
(header->prio == newAction->prio (header->prio == newAction->prio
&& header->interval > interval)) { && header->interval > interval)) {
@ -304,5 +321,38 @@ void DevSchedule(DevSer *devser, void *actionData,
newHeader->next = header; newHeader->next = header;
newHeader->timeDue = DoubleTime() + interval; newHeader->timeDue = DoubleTime() + interval;
*ptr2LastHeader = newHeader; *ptr2LastHeader = newHeader;
return; return ret;
}
int DevRemoveAction(DevSer *devser, void *actionData) {
SchedHeader *header = NULL;
DevAction **ptr2Last = NULL;
DevAction *action = NULL;
int cnt=0;
/* Remove current action, if matched. If a reply is pending, the next action will
get the reply. But as in the inital state no reply is expected, this should not harm. */
action = devser->current;
if (action != NULL && actionData == action->data) {
if (devser->killCurrent) {
if (action->kill != NULL) action->kill(action->data);
devser->killCurrent = 0;
free(action);
}
devser->current = NULL;
}
/* remove from queue */
ptr2Last = &devser->actions;
for (action = devser->actions; action != NULL; action = action->next) {
if (actionData == action->data) {
cnt++;
/* remove from list */
*ptr2Last = action->next;
if (action->kill != NULL) action->kill(action->data);
free(action);
} else {
ptr2Last = &action->next;
}
}
return cnt++;
} }

View File

@ -15,12 +15,12 @@ typedef struct DevSer DevSer;
*/ */
typedef char *DevActionHandler(void *actionData, char *lastReply); typedef char *DevActionHandler(void *actionData, char *lastReply);
/** \brief Check if two actions match /** \brief Check if an action matches the call data
* \param actionData1 the first action data * \param callData the callers data
* \param actionData2 the second action data * \param actionData the action data
* \return 1 on a match, 0 on no match * \return 1 on a match, 0 on no match
*/ */
typedef int DevActionMatch(void *actionData1, void *actionData2); typedef int DevActionMatch(void *callData, void *actionData);
/** \brief Kill ActionData /** \brief Kill ActionData
* \param actionData action data * \param actionData action data
@ -48,7 +48,9 @@ DevSer *DevMake(SConnection *con, int argc, char *argv[]);
*/ */
void DevDebugMode(DevSer *devser, int steps); void DevDebugMode(DevSer *devser, int steps);
/** \brief Kill the device serializer and its async connection. /** \brief Kill the contents of the device serializer and its async connection.
*
* The data structure itself is killed at some time later
* \param devser the device serializer * \param devser the device serializer
*/ */
void DevKill(DevSer *devser); void DevKill(DevSer *devser);
@ -79,24 +81,32 @@ void DevQueue(DevSer *devser, void *actionData, DevPrio prio,
* \param prio the priority * \param prio the priority
* \param interval the interval in seconds (0 is allowed) * \param interval the interval in seconds (0 is allowed)
* \param hdl the action handler * \param hdl the action handler
* \param matchFunc the match function * \param matchFunc the match function (callData must be of the same type as actionData)
* \param killFunc the action data kill function (called from DevKill and * \param killFunc the action data kill function (called from DevKill and
* from DevUnschedule) or NULL if no kill function is needed. * from DevUnschedule) or NULL if no kill function is needed.
* \return 0 when this was a new action, > 0 when an action was overwritten
*/ */
void DevSchedule(DevSer *devser, void *actionData, int DevSchedule(DevSer *devser, void *actionData,
DevPrio prio, double interval, DevPrio prio, double interval,
DevActionHandler hdl, DevActionMatch *matchFunc, DevActionHandler hdl, DevActionMatch *matchFunc,
DevKillActionData *killFunc); DevKillActionData *killFunc);
/** \brief Unschedule matching actions /** \brief Unschedule matching actions
* \param devser the device serializer * \param devser the device serializer
* \param actionData the action data to be compared for a match * \param callData the callers data to be as first argument of the match function
* \param hdl the action handler * \param hdl the action handler
* \param matchFunc the match function * \param matchFunc the match function (callData does not need to have the same type as actionData)
* \return the number of unscheduled actions
*/ */
int DevUnschedule(DevSer *devser, void *actionData, int DevUnschedule(DevSer *devser, void *actionData,
DevActionHandler hdl, DevActionMatch *matchFunc); DevActionHandler hdl, DevActionMatch *matchFunc);
/** \brief remove action from the serializer
* \param devser the device serializer
* \param actionData the action data to be compared for a match
*/
int DevRemoveAction(DevSer *devser, void *actionData);
/** \brief Convert integer priority to text /** \brief Convert integer priority to text
* \param prio * \param prio
* \return text * \return text

1
ofac.c
View File

@ -444,6 +444,7 @@
INIT(InitializerInit); INIT(InitializerInit);
INIT(SaveHdbInit); /* must be after InitializerInit */ INIT(SaveHdbInit); /* must be after InitializerInit */
INIT(SctInit); INIT(SctInit);
INIT(SctDriveInit);
INIT(LogReaderInit); INIT(LogReaderInit);
INIT(LogSetupInit); INIT(LogSetupInit);
INIT(StatusFileInit); INIT(StatusFileInit);

View File

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

33
scriptcontext.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef SCRIPTCONTEXT_H
#define SCRIPTCONTEXT_H
#include "sics.h"
#include "devser.h"
/* \brief an sct controller
*/
typedef struct SctController SctController;
/** \brief queue node action to a controller
*
* \param controller the controller
* \param node the node
* \param prio the priority
* \param action the initial state
* \param con an optional connection to be used by the action scripts
*/
void SctQueueNode(SctController *controller, Hdb *node,
DevPrio prio, char *action, SConnection *con);
/** \brief call a script and configure the sct command to be used
* in connection with the given node and controller
*
* \param con the connection
* \param script a tcl script
* \param the node to which the sct command
* \return 0 when this was a new action, > 0 when an action was overwritten
*/
int SctCallInContext(SConnection *con, char *script, Hdb *node,
SctController *controller, char **resPtr);
#endif

View File

@ -3,7 +3,7 @@
* scriptcontext generic device model. This is a wrapper around * scriptcontext generic device model. This is a wrapper around
* such a node which implements the drivable interface. * such a node which implements the drivable interface.
* *
* Soem cooperation from the node is required: It has to provide * Some cooperation from the node is required: It has to provide
* certain properties the value of which define scripts which * certain properties the value of which define scripts which
* have to be called at various stages. These are: * have to be called at various stages. These are:
* *
@ -21,13 +21,7 @@
#include <tcl.h> #include <tcl.h>
#include <macro.h> #include <macro.h>
#include <sicsobj.h> #include <sicsobj.h>
/*------------- Some things from scriptcontext.c ----------------*/ #include "scriptcontext.h"
typedef struct SctController SctController;
typedef struct SctData SctData;
SctData *SctQueueNode(SctController *controller, pHdb node,
DevPrio prio, char *action);
int SctCallInContext(SConnection *con, char *script, Hdb *node,
SctController *controller, char **resPtr);
/*---------------------------------------------------------------*/ /*---------------------------------------------------------------*/
typedef struct { typedef struct {
pObjectDescriptor pDes; pObjectDescriptor pDes;
@ -41,6 +35,7 @@ static void *SCTDRIVGetInterface(void *data, int iD){
self = (pSctDrive)data; self = (pSctDrive)data;
if(self != NULL && iD == DRIVEID){ if(self != NULL && iD == DRIVEID){
if (self->node == NULL) return NULL;
return self->pDriv; return self->pDriv;
} else { } else {
return NULL; return NULL;
@ -53,14 +48,14 @@ static void *SCTDRIVGetInterface(void *data, int iD){
------------------------------------------------------------------*/ ------------------------------------------------------------------*/
static int SCTDRIVHalt(void *data) { static int SCTDRIVHalt(void *data) {
pSctDrive self = NULL; pSctDrive self = NULL;
char dummy[16];
self = (pSctDrive)data; self = (pSctDrive)data;
SctQueueNode(self->c, self->node, HaltPRIO, "halt"); if (GetHdbProperty(self->node,"halt", dummy, sizeof dummy)) {
/* SctQueueNode(self->c, self->node, HaltPRIO, "halt", NULL);
* SctQueueNode returns a dynamically allocated SctData } else if (GetHdbProperty(self->node, "status", dummy, sizeof dummy)) {
* structure. I am not sure if this is not really a memory SetHdbProperty(self->node, "status", "idle");
* leak }
*/
return OKOK; return OKOK;
} }
/*---------------------------------------------------------------- /*----------------------------------------------------------------
@ -85,6 +80,7 @@ static int SCTDRIVCheckLimits(void *data, float val,
self->node, self->c, &result); self->node, self->c, &result);
if(status == 0){ if(status == 0){
strncpy(error,result,errlen); strncpy(error,result,errlen);
return 0;
} }
} }
return 1; return 1;
@ -132,31 +128,34 @@ static int SCTDRIVCheckStatus(void *data, SConnection *pCon){
self = (pSctDrive)data; self = (pSctDrive)data;
if(GetHdbProperty(self->node,"checkstatus",script,1024)){ if(!GetHdbProperty(self->node,"checkstatus",script,1024)){
status = SctCallInContext(pCon,script, self->node, if (!GetHdbProperty(self->node,"status",script,1024)){
self->c, &result); SCWrite(pCon,
if(status == 1){ "ERROR: configuration problem: no checkstatus script!", eError);
if(strstr(result,"busy") != NULL){ return HWFault;
return HWBusy; }
} else if(strstr(result,"posfault") != NULL){ result = script;
return HWPosFault;
} else if(strstr(result,"fault") != NULL){
return HWFault;
} else if(strstr(result,"idle") != NULL){
return HWIdle;
} else {
SCPrintf(pCon,eError,"ERROR: invalid status code %s returned from checkstatus script",
result);
return HWFault;
}
} else {
SCWrite(pCon,result, eError);
return HWFault;
}
} else { } else {
SCWrite(pCon, status = SctCallInContext(pCon,script, self->node,
"ERROR: configuration problem: no checkstatus script!", eError); self->c, &result);
return HWFault; if (status == 0) {
SCWrite(pCon,result, eError);
return HWFault;
}
}
if(strstr(result,"busy") != NULL){
return HWBusy;
} else if(strstr(result,"posfault") != NULL){
return HWPosFault;
} else if(strstr(result,"fault") != NULL){
return HWFault;
} else if(strstr(result,"idle") != NULL){
return HWIdle;
} else {
SCPrintf(pCon,eError,
"ERROR: invalid status code %s returned from checkstatus script",
result);
return HWFault;
} }
return HWFault; return HWFault;
} }
@ -212,6 +211,10 @@ static int SctDriveCommand(SConnection *pCon, SicsInterp *sics, void *object,
assert(self != NULL); assert(self != NULL);
if (self->node == NULL) {
SCWrite(pCon, "ERROR: defunct object", eError);
return 0;
}
/* /*
* only action: print value * only action: print value
*/ */
@ -234,15 +237,26 @@ static void SctDriveKill(void *data){
} }
free(self); free(self);
} }
/*----------------------------------------------------------------*/
static hdbCallbackReturn SctDummyCallback(Hdb *node, void *userData,
hdbMessage *msg) {
return hdbContinue;
}
/*----------------------------------------------------------------*/
static void SctDriveDeleteNode(void *data) {
pSctDrive self = (pSctDrive)data;
self->node = NULL;
}
/*---------------------------------------------------------------*/ /*---------------------------------------------------------------*/
int SctMakeDriveAdapter(SConnection *pCon, SicsInterp *pSics, void *object, int SctMakeDriveAdapter(SConnection *pCon, SicsInterp *pSics, void *object,
int argc, char *argv[]) { int argc, char *argv[]) {
pSctDrive pNew = NULL; pSctDrive pNew = NULL;
pSICSOBJ obj = NULL; pSICSOBJ obj = NULL;
hdbCallback *cb;
pNew = SCTDRIVMakeObject(); pNew = SCTDRIVMakeObject();
if(pNew == NULL){ if(pNew == NULL){
SCWrite(pCon,"ERROR: out of memory in SctmakeDriveAdapter", SCWrite(pCon,"ERROR: out of memory in SctMakeDriveAdapter",
eError); eError);
return 0; return 0;
} }
@ -260,7 +274,22 @@ int SctMakeDriveAdapter(SConnection *pCon, SicsInterp *pSics, void *object,
return 0; return 0;
} }
pNew->c =(SctController *)obj->pPrivate; pNew->c =(SctController *)obj->pPrivate;
if (strcasecmp(argv[0],"dynsctdrive") == 0) {
/* make object dynamic by defining a descriptor command */
SetDescriptorKey(pNew->pDes, "creationCommand", "0");
}
AddCommand(pSics, argv[1], SctDriveCommand, SctDriveKill, pNew); AddCommand(pSics, argv[1], SctDriveCommand, SctDriveKill, pNew);
SetHdbProperty(pNew->node,"sicsdev",argv[1]); SetHdbProperty(pNew->node,"sicsdev",argv[1]);
cb = MakeHipadabaCallback(SctDummyCallback, pNew, SctDriveDeleteNode);
assert(cb);
AppendHipadabaCallback(pNew->node, cb);
return 1; return 1;
} }
/*---------------------------------------------------------------*/
void SctDriveInit(void) {
AddCmd("makesctdrive", SctMakeDriveAdapter);
AddCmd("dynsctdrive", SctMakeDriveAdapter);
}