From 9e7a6cfd74a5327fde523e7e15309a49a353bd5e Mon Sep 17 00:00:00 2001 From: zolliker Date: Fri, 13 Jun 2008 11:22:13 +0000 Subject: [PATCH] - 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 unpoll - changed queuecon to send - some more improvements in sct --- devexec.c | 2 +- devser.c | 92 +++++++++++++---- devser.h | 28 ++++-- ofac.c | 1 + scriptcontext.c | 251 +++++++++++++++++++++++++++++++--------------- scriptcontext.h | 33 ++++++ sctdriveadapter.c | 109 ++++++++++++-------- 7 files changed, 366 insertions(+), 150 deletions(-) create mode 100644 scriptcontext.h diff --git a/devexec.c b/devexec.c index 7272490e..0a02f6ad 100644 --- a/devexec.c +++ b/devexec.c @@ -652,7 +652,7 @@ static int checkInterrupt(pCheckContext pCheck, int targetStatus){ } /*--------------------------------------------------------------------------*/ static int initializeCheck(pCheckContext pCheck, pDevEntry pDev){ - int eCode; + int eCode = HWFault; SCPushContext(pCheck->self->pOwner, pDev->comCon.transID, pDev->comCon.deviceID); diff --git a/devser.c b/devser.c index 7e21b2b2..3afbc848 100644 --- a/devser.c +++ b/devser.c @@ -26,8 +26,8 @@ struct DevSer { DevAction *actions; /* the action queue */ SchedHeader *headers; ErrMsg *errmsg; - int killMe; int steps; + int stopTask; }; static char *devPrio[NumberOfPRIO] = { @@ -59,10 +59,14 @@ static void DevFreeActionList(DevAction *actions) { } } -static void DevKillTask(void *devser) { - if(devser != NULL){ - DevKill(devser); - } +static void DevKillTask(void *ds) { + DevSer *devser = ds; + + if (devser->stopTask) { + free(devser); + } else { + devser->stopTask = 1; + } } DevAction *DevNextAction(DevSer *devser) { @@ -83,8 +87,12 @@ DevAction *DevNextAction(DevSer *devser) { if (header->followingAction == NULL) { if (now >= header->timeDue) { header->followingAction = header->actions; - header->timeDue = (floor(now / header->interval) + 1) - * header->interval; + if (header->interval <= 0) { + header->timeDue = now; + } else { + header->timeDue = (floor(now / header->interval) + 1) + * header->interval; + } } } if (header->followingAction != NULL) { @@ -110,7 +118,7 @@ int DevQueueTask(void *ds) { char *replyData; if (devser->steps == 0) return 1; - if (devser->killMe) { + if (devser->stopTask) { return 0; } action = devser->current; @@ -128,9 +136,9 @@ int DevQueueTask(void *ds) { devser->steps--; } if(status == AsconFailure){ - replyData = devser->errmsg->text; + replyData = devser->errmsg->text; } else { - replyData = AsconRead(devser->asyncConn); + replyData = AsconRead(devser->asyncConn); } sendData = action->hdl(action->data, replyData); if (sendData != NULL) { @@ -163,7 +171,7 @@ DevSer *DevMake(SConnection *con, int argc, char *argv[]) { devser->killCurrent = 0; devser->actions = NULL; devser->headers = NULL; - devser->killMe = 0; + devser->stopTask = 0; devser->steps = -1; /* no debugging by default */ TaskRegister(pServ->pTasker, DevQueueTask, NULL, DevKillTask, devser, 0); return devser; @@ -200,7 +208,11 @@ void DevKill(DevSer *devser) { DevFreeActionList(victim->actions); free(victim); } - devser->killMe = 1; + if (devser->stopTask) { + free(devser); + } else { + devser->stopTask = 1; + } } 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; ptr2Last = &devser->actions; 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 */ } ptr2Last = &action->next; @@ -234,11 +246,15 @@ int DevUnschedule(DevSer *devser, void *actionData, for (header = devser->headers; header != NULL; header = header->next) { ptr2Last = &header->actions; 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) { /* advance followingAction if equal*/ header->followingAction = action->next; } + if (action == devser->current) { + devser->current = NULL; + devser->killCurrent = 0; /* should already be 0 */ + } cnt++; /* remove from list */ *ptr2Last = action->next; @@ -252,20 +268,21 @@ int DevUnschedule(DevSer *devser, void *actionData, return cnt; } -void DevSchedule(DevSer *devser, void *actionData, - DevPrio prio, double interval, - DevActionHandler hdl, DevActionMatch *matchFunc, - DevKillActionData *killFunc) { +int DevSchedule(DevSer *devser, void *actionData, + DevPrio prio, double interval, + DevActionHandler hdl, DevActionMatch *matchFunc, + DevKillActionData *killFunc) { SchedHeader *header = NULL; SchedHeader **ptr2LastHeader = NULL; SchedHeader *newHeader; DevAction *action = NULL; DevAction **ptr2Last = NULL; DevAction *newAction; + int ret; if (prio <= NullPRIO) prio = NullPRIO + 1; if (prio >= NumberOfPRIO) prio = NumberOfPRIO - 1; - DevUnschedule(devser, actionData, hdl, matchFunc); + ret = DevUnschedule(devser, actionData, hdl, matchFunc); newAction = DevNewAction(actionData, hdl, killFunc, prio); /* find matching header */ @@ -279,7 +296,7 @@ void DevSchedule(DevSer *devser, void *actionData, } *ptr2Last = newAction; assert(newAction->next == NULL); - return; + return ret; } else if (header->prio < newAction->prio || (header->prio == newAction->prio && header->interval > interval)) { @@ -304,5 +321,38 @@ void DevSchedule(DevSer *devser, void *actionData, newHeader->next = header; newHeader->timeDue = DoubleTime() + interval; *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++; } diff --git a/devser.h b/devser.h index f0a4b722..95f29a8a 100644 --- a/devser.h +++ b/devser.h @@ -15,12 +15,12 @@ typedef struct DevSer DevSer; */ typedef char *DevActionHandler(void *actionData, char *lastReply); -/** \brief Check if two actions match - * \param actionData1 the first action data - * \param actionData2 the second action data +/** \brief Check if an action matches the call data + * \param callData the callers data + * \param actionData the action data * \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 * \param actionData action data @@ -48,7 +48,9 @@ DevSer *DevMake(SConnection *con, int argc, char *argv[]); */ 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 */ void DevKill(DevSer *devser); @@ -79,24 +81,32 @@ void DevQueue(DevSer *devser, void *actionData, DevPrio prio, * \param prio the priority * \param interval the interval in seconds (0 is allowed) * \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 * 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, DevActionHandler hdl, DevActionMatch *matchFunc, DevKillActionData *killFunc); /** \brief Unschedule matching actions * \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 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, 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 * \param prio * \return text diff --git a/ofac.c b/ofac.c index 073b0443..1bc2c26a 100644 --- a/ofac.c +++ b/ofac.c @@ -444,6 +444,7 @@ INIT(InitializerInit); INIT(SaveHdbInit); /* must be after InitializerInit */ INIT(SctInit); + INIT(SctDriveInit); INIT(LogReaderInit); INIT(LogSetupInit); INIT(StatusFileInit); diff --git a/scriptcontext.c b/scriptcontext.c index d853aded..3152ecd1 100644 --- a/scriptcontext.c +++ b/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 ""; -} - -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 ()", + 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 ", + SCPrintf(con,eError, + "ERROR: should be: %s queue ", 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); } diff --git a/scriptcontext.h b/scriptcontext.h new file mode 100644 index 00000000..75ccca22 --- /dev/null +++ b/scriptcontext.h @@ -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 diff --git a/sctdriveadapter.c b/sctdriveadapter.c index af209ae6..f4333c61 100644 --- a/sctdriveadapter.c +++ b/sctdriveadapter.c @@ -3,7 +3,7 @@ * scriptcontext generic device model. This is a wrapper around * 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 * have to be called at various stages. These are: * @@ -21,13 +21,7 @@ #include #include #include -/*------------- Some things from scriptcontext.c ----------------*/ -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); +#include "scriptcontext.h" /*---------------------------------------------------------------*/ typedef struct { pObjectDescriptor pDes; @@ -41,6 +35,7 @@ static void *SCTDRIVGetInterface(void *data, int iD){ self = (pSctDrive)data; if(self != NULL && iD == DRIVEID){ + if (self->node == NULL) return NULL; return self->pDriv; } else { return NULL; @@ -53,14 +48,14 @@ static void *SCTDRIVGetInterface(void *data, int iD){ ------------------------------------------------------------------*/ static int SCTDRIVHalt(void *data) { pSctDrive self = NULL; - + char dummy[16]; + self = (pSctDrive)data; - SctQueueNode(self->c, self->node, HaltPRIO, "halt"); - /* - * SctQueueNode returns a dynamically allocated SctData - * structure. I am not sure if this is not really a memory - * leak - */ + if (GetHdbProperty(self->node,"halt", dummy, sizeof dummy)) { + SctQueueNode(self->c, self->node, HaltPRIO, "halt", NULL); + } else if (GetHdbProperty(self->node, "status", dummy, sizeof dummy)) { + SetHdbProperty(self->node, "status", "idle"); + } return OKOK; } /*---------------------------------------------------------------- @@ -85,6 +80,7 @@ static int SCTDRIVCheckLimits(void *data, float val, self->node, self->c, &result); if(status == 0){ strncpy(error,result,errlen); + return 0; } } return 1; @@ -132,31 +128,34 @@ static int SCTDRIVCheckStatus(void *data, SConnection *pCon){ self = (pSctDrive)data; - if(GetHdbProperty(self->node,"checkstatus",script,1024)){ - status = SctCallInContext(pCon,script, self->node, - self->c, &result); - if(status == 1){ - 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; - } - } else { - SCWrite(pCon,result, eError); - return HWFault; - } + if(!GetHdbProperty(self->node,"checkstatus",script,1024)){ + if (!GetHdbProperty(self->node,"status",script,1024)){ + SCWrite(pCon, + "ERROR: configuration problem: no checkstatus script!", eError); + return HWFault; + } + result = script; } else { - SCWrite(pCon, - "ERROR: configuration problem: no checkstatus script!", eError); - return HWFault; + status = SctCallInContext(pCon,script, self->node, + self->c, &result); + 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; } @@ -212,6 +211,10 @@ static int SctDriveCommand(SConnection *pCon, SicsInterp *sics, void *object, assert(self != NULL); + if (self->node == NULL) { + SCWrite(pCon, "ERROR: defunct object", eError); + return 0; + } /* * only action: print value */ @@ -234,15 +237,26 @@ static void SctDriveKill(void *data){ } 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 argc, char *argv[]) { pSctDrive pNew = NULL; pSICSOBJ obj = NULL; + hdbCallback *cb; pNew = SCTDRIVMakeObject(); if(pNew == NULL){ - SCWrite(pCon,"ERROR: out of memory in SctmakeDriveAdapter", + SCWrite(pCon,"ERROR: out of memory in SctMakeDriveAdapter", eError); return 0; } @@ -260,7 +274,22 @@ int SctMakeDriveAdapter(SConnection *pCon, SicsInterp *pSics, void *object, return 0; } 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); SetHdbProperty(pNew->node,"sicsdev",argv[1]); + + cb = MakeHipadabaCallback(SctDummyCallback, pNew, SctDriveDeleteNode); + assert(cb); + AppendHipadabaCallback(pNew->node, cb); + return 1; } +/*---------------------------------------------------------------*/ +void SctDriveInit(void) { + AddCmd("makesctdrive", SctMakeDriveAdapter); + AddCmd("dynsctdrive", SctMakeDriveAdapter); +}