- simplified devser queue

- added inherited sct variables starting with @
- inserted SctIsPending / DevIsPending
- some general improvements in scriptcontext.c/sctdriveobj.c
This commit is contained in:
zolliker
2010-01-27 13:39:33 +00:00
parent 7976b52212
commit a56838b90d
5 changed files with 303 additions and 246 deletions

366
devser.c
View File

@ -8,24 +8,16 @@ typedef struct DevAction {
DevActionHandler *hdl; DevActionHandler *hdl;
DevPrio prio; DevPrio prio;
DevKillActionData *kill; DevKillActionData *kill;
double interval; /* -1 for a queued action */
double timeDue; /* 0 for a queued action */
} DevAction; } DevAction;
typedef struct SchedHeader {
struct SchedHeader *next;
DevAction *actions; /* list of actions for given interval and prio */
DevAction *followingAction;
double interval;
double timeDue;
DevPrio prio;
} SchedHeader;
struct DevSer { struct DevSer {
Ascon *asyncConn; /* connection */ Ascon *ascon; /* connection */
DevAction *current; DevAction *current;
int killCurrent; int killCurrent;
DevAction *actions; /* the action queue */ DevAction *actions; /* the action queue */
DevAction *toKill; /* list of actions to be killed */ DevAction *toKill; /* list of actions to be killed */
SchedHeader *headers;
int steps; int steps;
}; };
@ -65,52 +57,81 @@ static void DevFreeActionList(DevAction * actions)
} }
} }
DevAction *DevNextAction(DevSer * devser) static double nextTime(double last,
{ double lastInterval,
DevPrio prio; double now,
double now; double interval) {
SchedHeader *header; double base;
/* nextTime gives the next possible time according to the
* following rules:
devser->current = NULL; * (1) result > now
if (devser->actions) { * (2) result is a multiple of interval
prio = devser->actions->prio; * (3) result > last + min(lastInterval,interval) * 0.99
*/
if (interval > lastInterval) {
base = last + lastInterval * 0.99;
} else { } else {
prio = NullPRIO; base = last + interval * 0.99;
} }
now = DoubleTime(); if (now > base) {
for (header = devser->headers; base = now;
header != NULL && header->prio > prio; header = header->next) {
if (header->followingAction == NULL) {
if (now >= header->timeDue) {
header->followingAction = header->actions;
if (header->interval <= 0) {
header->timeDue = now;
} else {
header->timeDue = (floor(now / header->interval) + 1)
* header->interval;
} }
} else if (header->prio == StartPRIO && header->actions != NULL) { return (floor(base / interval) + 1) * interval;
/* special case: poll with StartPRIO pending: block all other actions */
return devser->current;
}
}
if (header->followingAction != NULL) {
devser->current = header->followingAction;
devser->killCurrent = 0;
header->followingAction = header->followingAction->next;
return devser->current;
}
}
if (devser->actions) {
devser->current = devser->actions;
devser->killCurrent = 1;
devser->actions = devser->actions->next;
}
return devser->current;
} }
int DevQueueTask(void *ds) static DevAction *DevNextAction(DevSer * devser)
{
/* the action queue is primarily ordered by priority (high prioirty first),
* within one priority by usage (last used action at end)
*/
DevPrio prio;
double now, next;
DevAction *action, **ptr2prev;
devser->current = NULL;
now = DoubleTime();
for (ptr2prev = &devser->actions, action = devser->actions;
action != NULL;
ptr2prev = &action->next, action = action->next) {
if (now >= action->timeDue) {
/* remove action from queue */
*ptr2prev = action->next;
devser->current = action;
if (action->interval >= 0) {
/* this is a scheduled action, to be preserved after use */
devser->killCurrent = 0;
if (action->interval == 0) {
action->timeDue = now;
} else {
/* increase timeDue according to interval */
action->timeDue = nextTime(action->timeDue, action->interval,
now, action->interval);
}
prio = action->prio;
/* insert devser->current before the next lower priority */
for (action = action->next; /* start after this */
action != NULL && action->prio >= prio;
ptr2prev = &action->next, action = action->next);
/* action is now NULL or the next action with lower priority */
*ptr2prev = devser->current;
devser->current->next = action;
} else {
/* this is a queued action, to be killed after use */
devser->killCurrent = 1;
}
return devser->current;
}
if (action->prio == StartPRIO) {
/* if a poll with StartPRIO is scheduled, block all other actions */
return NULL;
}
}
return NULL;
}
static int DevQueueTask(void *ds)
{ {
DevSer *devser = ds; DevSer *devser = ds;
AsconStatus status; AsconStatus status;
@ -131,11 +152,11 @@ int DevQueueTask(void *ds)
} }
while (action != NULL) { while (action != NULL) {
status = AsconTask(devser->asyncConn); status = AsconTask(devser->ascon);
if (status == AsconFailure) { if (status == AsconFailure) {
replyData = AsconGetError(devser->asyncConn); replyData = AsconGetError(devser->ascon);
} else if (status == AsconReady) { } else if (status == AsconReady) {
replyData = AsconRead(devser->asyncConn); replyData = AsconRead(devser->ascon);
} else { } else {
return 1; return 1;
} }
@ -144,7 +165,7 @@ int DevQueueTask(void *ds)
} }
sendData = action->hdl(action->data, replyData, (status == AsconFailure)); sendData = action->hdl(action->data, replyData, (status == AsconFailure));
if (sendData != NULL) { if (sendData != NULL) {
AsconWrite(devser->asyncConn, sendData, 0); AsconWrite(devser->ascon, sendData, 0);
return 1; return 1;
} }
if (devser->killCurrent) { if (devser->killCurrent) {
@ -162,19 +183,18 @@ int DevQueueTask(void *ds)
DevSer *DevMake(SConnection * con, int argc, char *argv[]) DevSer *DevMake(SConnection * con, int argc, char *argv[])
{ {
DevSer *devser = NULL; DevSer *devser = NULL;
Ascon *asyncConn = NULL; Ascon *ascon = NULL;
asyncConn = AsconMake(con, argc, argv); ascon = AsconMake(con, argc, argv);
if (!asyncConn) { if (!ascon) {
return NULL; return NULL;
} }
devser = calloc(1, sizeof(*devser)); devser = calloc(1, sizeof(*devser));
assert(devser); assert(devser);
devser->asyncConn = asyncConn; devser->ascon = ascon;
devser->current = NULL; devser->current = NULL;
devser->killCurrent = 0; devser->killCurrent = 0;
devser->actions = NULL; devser->actions = NULL;
devser->headers = NULL;
devser->toKill = NULL; devser->toKill = NULL;
devser->steps = -1; /* no debugging by default */ devser->steps = -1; /* no debugging by default */
TaskRegister(pServ->pTasker, DevQueueTask, NULL, NULL, devser, 0); TaskRegister(pServ->pTasker, DevQueueTask, NULL, NULL, devser, 0);
@ -186,38 +206,17 @@ void DevDebugMode(DevSer * devser, int steps)
devser->steps = steps; devser->steps = steps;
} }
DevAction *DevNewAction(void *data, DevActionHandler hdl,
DevKillActionData * killFunc, DevPrio prio)
{
DevAction *action;
action = calloc(1, sizeof(*action));
assert(action);
action->data = data;
action->hdl = hdl;
action->kill = killFunc;
action->prio = prio;
action->next = NULL;
return action;
}
void DevKill(DevSer * devser) void DevKill(DevSer * devser)
{ {
SchedHeader *h, *victim; if (devser->ascon) {
AsconKill(devser->ascon);
if (devser->asyncConn) {
AsconKill(devser->asyncConn);
} }
DevFreeActionList(devser->actions); DevFreeActionList(devser->actions);
DevFreeActionList(devser->toKill); DevFreeActionList(devser->toKill);
h = devser->headers;
while (h != NULL) {
victim = h;
h = victim->next;
DevFreeActionList(victim->actions);
free(victim);
}
if (devser->killCurrent) { if (devser->killCurrent) {
if (devser->current->kill != NULL) devser->current->kill(devser->current); if (devser->current->kill != NULL) {
devser->current->kill(devser->current);
}
devser->killCurrent = 0; devser->killCurrent = 0;
free(devser->current); free(devser->current);
} }
@ -227,67 +226,35 @@ void DevKill(DevSer * devser)
void DevDisconnect(DevSer * devser) void DevDisconnect(DevSer * devser)
{ {
if (devser->asyncConn) { if (devser->ascon) {
AsconDisconnect(devser->asyncConn); AsconDisconnect(devser->ascon);
} }
} }
int DevQueue(DevSer * devser, void *actionData, DevPrio prio, int DevUnschedule(DevSer * devser, void *callData,
DevActionHandler hdl, DevActionMatch * matchFunc, DevActionHandler * hdl, DevActionMatch * matchFunc)
DevKillActionData * killFunc)
{ {
DevAction *action, **ptr2Last; DevAction **ptr2prev = NULL;
DevAction *new;
if (prio <= NullPRIO)
prio = NullPRIO + 1;
if (prio >= NumberOfPRIO)
prio = NumberOfPRIO - 1;
ptr2Last = &devser->actions;
for (action = devser->actions; action != NULL && action->prio >= prio;
action = action->next) {
if (action->hdl == hdl && matchFunc(actionData, action->data)) {
return 0; /* there is already an identical action */
}
ptr2Last = &action->next;
}
new = DevNewAction(actionData, hdl, killFunc, prio);
new->next = action;
*ptr2Last = new;
return 1;
}
int DevUnschedule(DevSer * devser, void *actionData,
DevActionHandler hdl, DevActionMatch * matchFunc)
{
SchedHeader *header = NULL;
DevAction **ptr2Last = NULL;
DevAction *action = NULL; DevAction *action = NULL;
int cnt = 0; int cnt = 0;
/* scan through all headers */ /* scan through the queue */
for (header = devser->headers; header != NULL; header = header->next) { for (ptr2prev = &devser->actions, action = devser->actions;
ptr2Last = &header->actions; action != NULL;
for (action = header->actions; action != NULL; action = *ptr2Last) { action = action->next) {
if (action->hdl == hdl && matchFunc(actionData, action->data)) { if (action->hdl == hdl && matchFunc(callData, action->data)) {
if (action == header->followingAction) {
/* advance followingAction if equal */
header->followingAction = action->next;
}
if (action == devser->current) { if (action == devser->current) {
devser->current = NULL; devser->current = NULL;
devser->killCurrent = 0; /* should already be 0 */ devser->killCurrent = 0;
} }
cnt++; cnt++;
/* remove from list */ /* remove from list */
*ptr2Last = action->next; *ptr2prev = action->next;
/* add to kill list */ /* add to kill list */
action->next = devser->toKill; action->next = devser->toKill;
devser->toKill = action; devser->toKill = action;
} else { } else {
ptr2Last = &action->next; ptr2prev = &action->next;
}
} }
} }
return cnt; return cnt;
@ -295,67 +262,92 @@ int DevUnschedule(DevSer * devser, void *actionData,
int 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; DevAction *action;
SchedHeader **ptr2LastHeader = NULL; DevAction *foundAction = NULL;
SchedHeader *newHeader; DevAction **ptr2prev;
DevAction *action = NULL; DevAction **ptr2insertPos = NULL;
DevAction **ptr2Last = NULL;
DevAction *newAction;
int ret; int ret;
if (prio <= NullPRIO) if (prio <= NullPRIO) {
prio = NullPRIO + 1; prio = NullPRIO + 1;
if (prio >= NumberOfPRIO) }
if (prio >= NumberOfPRIO) {
prio = NumberOfPRIO - 1; prio = NumberOfPRIO - 1;
ret = DevUnschedule(devser, actionData, hdl, matchFunc); }
newAction = DevNewAction(actionData, hdl, killFunc, prio); for (ptr2prev = &devser->actions, action = devser->actions;
/* find matching header */ action != NULL;
ptr2LastHeader = &devser->headers; ptr2prev = &action->next, action = action->next) {
for (header = devser->headers; header != NULL; header = *ptr2LastHeader) { if (action->prio < prio && ptr2insertPos == NULL) {
if (header->prio == newAction->prio && header->interval == interval) { ptr2insertPos = ptr2prev;
/* append new action at the tail */
ptr2Last = &header->actions;
for (action = header->actions; action != NULL; action = action->next) {
ptr2Last = &action->next;
} }
*ptr2Last = newAction; /* check if it is the same action (only once) */
assert(newAction->next == NULL); if (action->hdl == hdl
return ret; && action->kill == killFunc
} else if (header->prio < newAction->prio || && (interval < 0) == (action->interval < 0)
(header->prio == newAction->prio && foundAction == NULL
&& header->interval > interval)) { && matchFunc(actionData, action->data)) {
break; if (prio == action->prio && interval < 0) {
/* do not move an action with equal prio */
killFunc(actionData);
return 0;
} }
if (header->actions == NULL) { /* remove action from list */
/* remove empty header */ *ptr2prev = action->next;
*ptr2LastHeader = header->next; foundAction = action;
free(header); }
}
/* create if needed */
if (foundAction != NULL) {
action = foundAction;
ret = 0;
killFunc(actionData);
} else { } else {
ptr2LastHeader = &header->next; action = calloc(1, sizeof(*action));
} assert(action);
action->data = actionData;
action->hdl = hdl;
action->kill = killFunc;
action->timeDue = 0;
ret = 1;
} }
/* insert new header */ action->prio = prio;
newHeader = calloc(1, sizeof(*newHeader)); /* insert into queue */
assert(newHeader); if (ptr2insertPos == NULL) {
newHeader->actions = newAction; ptr2insertPos = ptr2prev;
newHeader->followingAction = NULL; }
newHeader->prio = newAction->prio; action->next = *ptr2insertPos;
newHeader->interval = interval; *ptr2insertPos = action;
newHeader->next = header;
newHeader->timeDue = DoubleTime() + interval; if (interval < 0) { /* case "queued" */
*ptr2LastHeader = newHeader; action->interval = -1.0;
} else { /* case "scheduled" */
if (action->timeDue == 0) { /* not yet scheduled: do it immediately */
action->timeDue = DoubleTime();
} else { /* calculate next time */
action->timeDue = nextTime(action->timeDue, action->interval,
DoubleTime(), interval);
}
action->interval = interval;
}
return ret; return ret;
} }
int DevQueue(DevSer * devser, void *actionData, DevPrio prio,
DevActionHandler * hdl, DevActionMatch * matchFunc,
DevKillActionData * killFunc)
{
return DevSchedule(devser, actionData, prio, -1.0, hdl, matchFunc, killFunc);
}
int DevRemoveAction(DevSer * devser, void *actionData) int DevRemoveAction(DevSer * devser, void *actionData)
{ {
SchedHeader *header = NULL; DevAction **ptr2prev = NULL;
DevAction **ptr2Last = NULL;
DevAction *action = NULL; DevAction *action = NULL;
int cnt = 0; int cnt = 0;
@ -374,18 +366,32 @@ int DevRemoveAction(DevSer * devser, void *actionData)
devser->current = NULL; devser->current = NULL;
} }
/* remove from queue */ /* remove from queue */
ptr2Last = &devser->actions; ptr2prev = &devser->actions;
for (action = devser->actions; action != NULL; action = *ptr2Last) { for (action = devser->actions; action != NULL; action = *ptr2prev) {
if (actionData == action->data) { if (actionData == action->data) {
cnt++; cnt++;
/* remove from list */ /* remove from list */
*ptr2Last = action->next; *ptr2prev = action->next;
if (action->kill != NULL) if (action->kill != NULL)
action->kill(action->data); action->kill(action->data);
free(action); free(action);
} else { } else {
ptr2Last = &action->next; ptr2prev = &action->next;
} }
} }
return cnt++; return cnt++;
} }
int DevIsPending(DevSer * devser, void *callData,
DevActionHandler * hdl, DevActionMatch * matchFunc)
{
DevAction *action = devser->current;
if (action) {
if (action->hdl == hdl && matchFunc(callData, action->data)) {
return 1;
}
}
return 0;
}

View File

@ -72,15 +72,15 @@ void DevDisconnect(DevSer * devser);
* \param actionData the action data * \param actionData the action data
* \param prio the priority * \param prio the priority
* \param hdl the action handler * \param hdl the action handler
* \param matchFunc the match function * \param matchFunc a match function with two arguments of the same type
* \param killFunc the action data kill function (called from DevKill and * \param killFunc the action data kill function (called from DevKill and
* after the action has finished, i.e. when hdl returned NULL) * after the action has finished, i.e. when hdl returned NULL)
* or NULL if no kill function is needed. * or NULL if no kill function is needed.
* \return 0 when not queued because a similar action is already on the queue, * \return 1 when this was a new action, 0 when an action was overwritten
* 1 on success. * in the second case the actionData's kill Function is called
*/ */
int DevQueue(DevSer * devser, void *actionData, DevPrio prio, int DevQueue(DevSer * devser, void *actionData, DevPrio prio,
DevActionHandler hdl, DevActionMatch * matchFunc, DevActionHandler * hdl, DevActionMatch * matchFunc,
DevKillActionData * killFunc); DevKillActionData * killFunc);
/** \brief Schedule a periodic action /** \brief Schedule a periodic action
@ -92,25 +92,25 @@ int 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 (callData must be of the same type as actionData) * \param matchFunc a match function with two arguments of the same type
* \param killFunc the action data kill function (called from DevKill and * \param killFunc the action data kill function or NULL if no kill function is needed.
* from DevUnschedule) or NULL if no kill function is needed. * \return 1 when this was a new action, 0 when an action was overwritten
* \return 0 when this was a new action, > 0 when an action was overwritten * in the second case the actionData's kill Function is called
*/ */
int 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 callers data to be used as first argument of the match function * \param callData the callers data to be used as first argument of the match function
* \param hdl the action handler * \param hdl the action handler
* \param matchFunc the match function (callData does not need to have the same type as actionData) * \param matchFunc a match function (the first argument might have an other type than the second)
* \return the number of unscheduled actions * \return the number of unscheduled actions
*/ */
int DevUnschedule(DevSer * devser, void *actionData, int DevUnschedule(DevSer * devser, void *callData,
DevActionHandler hdl, DevActionMatch * matchFunc); DevActionHandler * hdl, DevActionMatch * matchFunc);
/** \brief remove action from the serializer /** \brief remove action from the serializer
* \param devser the device serializer * \param devser the device serializer
@ -118,6 +118,15 @@ int DevUnschedule(DevSer * devser, void *actionData,
*/ */
int DevRemoveAction(DevSer * devser, void *actionData); int DevRemoveAction(DevSer * devser, void *actionData);
/** \brief check if an action is pending
* \param devser the device serializer
* \param callData the callers data to be used as first argument of the match function
* \param hdl the action handler
* \param matchFunc a match function (the first argument might have an other type than the second)
* \return the number of unscheduled actions
*/
int DevIsPending(DevSer * devser, void *callData,
DevActionHandler * hdl, DevActionMatch * matchFunc);
/** \brief Convert integer priority to text /** \brief Convert integer priority to text
* \param prio * \param prio

View File

@ -54,8 +54,6 @@ static struct {
char *name; char *name;
} actionCallback; } actionCallback;
static char *mainCallback = "main callback";
void PushContext(Hdb * node, Hdb * controllerNode) void PushContext(Hdb * node, Hdb * controllerNode)
{ {
ContextItem *new; ContextItem *new;
@ -98,45 +96,58 @@ void CleanStack(Hdb * node)
} }
} }
static void SetProp(Hdb * node, Hdb * cNode, char *key, char *value) static char *GetPropAndNode(Hdb * node, Hdb * cNode, char *key, Hdb **foundNode)
{ {
char *val; char *val;
Hdb *mama;
if (node == NULL) { if (key[0] == '@') {
if (cNode == NULL) /* for keys starting with @ look also at the ancestors */
return; for (mama = node; mama != NULL; mama = mama->mama) {
node = cNode; val = GetHdbProp(mama, key);
} else { if (val != NULL) {
*foundNode = mama;
return val;
}
}
}
if (node != NULL) {
val = GetHdbProp(node, key); val = GetHdbProp(node, key);
if (val == NULL && cNode != NULL) { if (val != NULL) {
*foundNode = node;
return val;
}
}
if (cNode != NULL) {
val = GetHdbProp(cNode, key); val = GetHdbProp(cNode, key);
if (val != NULL) { if (val != NULL) {
node = cNode; *foundNode = cNode;
} return val;
} }
} }
*foundNode = node;
return NULL;
}
static void SetProp(Hdb * node, Hdb * cNode, char *key, char *value)
{
Hdb *propNode;
char *val;
val = GetPropAndNode(node, cNode, key, &propNode);
if (value == NULL) { if (value == NULL) {
if (GetHdbProperty(node, key, NULL, 0) > 0) { if (val != NULL) {
SetHdbProperty(node, key, ""); SetHdbProperty(propNode, key, "");
} }
} else { } else {
SetHdbProperty(node, key, value); SetHdbProperty(propNode, key, value);
} }
} }
static char *GetProp(Hdb * node, Hdb * cNode, char *key) static char *GetProp(Hdb * node, Hdb * cNode, char *key)
{ {
char *val; Hdb *propNode;
return GetPropAndNode(node, cNode, key, &propNode);
if (node != NULL) {
val = GetHdbProp(node, key);
if (val != NULL)
return val;
}
if (cNode != NULL) {
val = GetHdbProp(cNode, key);
}
return val;
} }
/* /*
@ -302,6 +313,7 @@ static int SctMatch(void *data1, void *data2)
return a->node == b->node && strcasecmp(a->name, b->name) == 0; return a->node == b->node && strcasecmp(a->name, b->name) == 0;
} }
/* /*
* This routine is running the script chain. It is called repeatedly * This routine is running the script chain. It is called repeatedly
* with response data from the device serializer (devser). This function * with response data from the device serializer (devser). This function
@ -350,7 +362,7 @@ static char *SctActionHandler(void *actionData, char *lastReply,
script = NULL; script = NULL;
if (!commError && controller->verbose && lastReply != NULL if (!commError && controller->verbose && lastReply != NULL
&& *lastReply != '\0') { && *lastReply != '\0') {
SCPrintf(con, eLog, "reply : %s", lastReply); SCPrintf(con, eLog, "reply : %s\n", lastReply);
} }
/* /*
@ -534,7 +546,7 @@ static int SctMatchNode(void *vNode, void *vData)
} }
/* /*
* This is the read callback for nodes participating in the * This is the callback for all nodes participating in the
* scriptcontext system * scriptcontext system
*/ */
static hdbCallbackReturn SctMainCallback(Hdb * node, void *userData, static hdbCallbackReturn SctMainCallback(Hdb * node, void *userData,
@ -584,8 +596,8 @@ static hdbCallbackReturn SctMainCallback(Hdb * node, void *userData,
if (geterror != NULL) { if (geterror != NULL) {
snprintf(error,255,"ERROR: %s", geterror); snprintf(error,255,"ERROR: %s", geterror);
SCWrite(con, error, eError); SCWrite(con, error, eError);
if(mm->v->dataType == HIPTEXT){ if (mm->v->dataType == HIPTEXT) {
if(mm->v->v.text != NULL){ if (mm->v->v.text != NULL) {
free(mm->v->v.text); free(mm->v->v.text);
} }
mm->v->v.text = strdup(error); mm->v->v.text = strdup(error);
@ -982,11 +994,7 @@ void SctQueueNode(SctController * controller, Hdb * node,
SctData *data; SctData *data;
hdbCallback *cb; hdbCallback *cb;
/* if (!FindHdbCallbackData(node, controller)) {
* The test for read below is questionable. If this becomes a problem
* take it out and tell Mark and Markus about the fact.
*/
if (!FindHdbCallbackData(node, controller) && strcmp(action,"read") == 0) {
cb = MakeHipadabaCallback(SctMainCallback, controller, NULL); cb = MakeHipadabaCallback(SctMainCallback, controller, NULL);
assert(cb); assert(cb);
AppendHipadabaCallback(node, cb); AppendHipadabaCallback(node, cb);
@ -1207,9 +1215,12 @@ static void SctKillController(void *c)
{ {
SctController *controller = c; SctController *controller = c;
SConnection *con; SConnection *con;
hdbPtrMessage m;
CleanStack(controller->node); CleanStack(controller->node);
RemoveSICSInternalCallback(controller); RemoveSICSInternalCallback(controller);
RemoveSICSInternalCallbackFrom(controller->node, controller);
if (controller->conn) { if (controller->conn) {
SCDeleteConnection(controller->conn); SCDeleteConnection(controller->conn);
} }
@ -1361,3 +1372,20 @@ int SctVerbose(SctController * c)
{ {
return c->verbose; return c->verbose;
} }
int SctIsPending(SctController *controller, Hdb * node, char *name, int kind)
{
void *currentAction;
SctData data;
data.node = node;
data.name = name;
switch (kind) {
case 0:
return DevIsPending(controller->devser, &data, SctWriteHandler, SctMatch);
case 1:
return DevIsPending(controller->devser, &data, SctActionHandler, SctMatch);
default:
return 0;
}
}

View File

@ -35,4 +35,15 @@ int SctCallInContext(SConnection * con, char *script, Hdb * node,
* \return 1 for verbose, 0 for silent * \return 1 for verbose, 0 for silent
*/ */
int SctVerbose(SctController * c); int SctVerbose(SctController * c);
/**
* check if the specified action is pending
* \param controller the SctController
* \param node the node
* \param name the action
* \param kind 0 for queued action, 1 for polled action
* \return 1 for pending, 0 for not pending
*/
int SctIsPending(SctController *controller, Hdb * node, char *name, int kind);
#endif #endif

View File

@ -107,7 +107,8 @@ static int SCTDRIVCheckLimits(void *data, float val,
self = (pSICSOBJ) data; self = (pSICSOBJ) data;
pPriv = (pDrivObjPriv) self->pPrivate; pPriv = (pDrivObjPriv) self->pPrivate;
snprintf(script, 1024, "%f", val); snprintf(script, 1024, "%g", val);
/* set target. This not yet done, as SetValue is called later */
SetHdbProperty(self->objectNode, "target", script); SetHdbProperty(self->objectNode, "target", script);
if (GetHdbProperty(self->objectNode, "checklimits", script, 1024)) { if (GetHdbProperty(self->objectNode, "checklimits", script, 1024)) {
status = SctCallInContext(pServ->dummyCon, script, status = SctCallInContext(pServ->dummyCon, script,
@ -298,6 +299,7 @@ pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController * c,
memset(pPriv, 0, sizeof(DrivObjPriv)); memset(pPriv, 0, sizeof(DrivObjPriv));
pNew->pDes = CreateDescriptor(class); pNew->pDes = CreateDescriptor(class);
pNew->pDes->SaveStatus = SaveSICSOBJ;
pPriv->pDriv = CreateDrivableInterface(); pPriv->pDriv = CreateDrivableInterface();
if (pNew->pDes == NULL || pPriv->pDriv == NULL) { if (pNew->pDes == NULL || pPriv->pDriv == NULL) {
free(pNew); free(pNew);
@ -357,6 +359,7 @@ int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics,
SCWrite(pCon, "ERROR: node creation failed", eError); SCWrite(pCon, "ERROR: node creation failed", eError);
return 0; return 0;
} }
SetHdbProperty(node, "sicscommand", argv[1]);
sctName = argv[5]; sctName = argv[5];
class = argv[4]; class = argv[4];
doNotKillNode = 0; /* kill the node with the command */ doNotKillNode = 0; /* kill the node with the command */