- 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:
366
devser.c
366
devser.c
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
35
devser.h
35
devser.h
@ -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
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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 */
|
||||||
|
Reference in New Issue
Block a user