- added scriptcontext.h
- killing a node using sct should now be safe - sctdrive adapter object might be dynamic - default for the checkstatus script: returning the status property - introduced <sctcon> unpoll - changed <sctcon> queuecon to <sctcon> send - some more improvements in sct
This commit is contained in:
@ -652,7 +652,7 @@ static int checkInterrupt(pCheckContext pCheck, int targetStatus){
|
|||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
static int initializeCheck(pCheckContext pCheck, pDevEntry pDev){
|
static int initializeCheck(pCheckContext pCheck, pDevEntry pDev){
|
||||||
int eCode;
|
int eCode = HWFault;
|
||||||
|
|
||||||
SCPushContext(pCheck->self->pOwner,
|
SCPushContext(pCheck->self->pOwner,
|
||||||
pDev->comCon.transID, pDev->comCon.deviceID);
|
pDev->comCon.transID, pDev->comCon.deviceID);
|
||||||
|
92
devser.c
92
devser.c
@ -26,8 +26,8 @@ struct DevSer {
|
|||||||
DevAction *actions; /* the action queue */
|
DevAction *actions; /* the action queue */
|
||||||
SchedHeader *headers;
|
SchedHeader *headers;
|
||||||
ErrMsg *errmsg;
|
ErrMsg *errmsg;
|
||||||
int killMe;
|
|
||||||
int steps;
|
int steps;
|
||||||
|
int stopTask;
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *devPrio[NumberOfPRIO] = {
|
static char *devPrio[NumberOfPRIO] = {
|
||||||
@ -59,10 +59,14 @@ static void DevFreeActionList(DevAction *actions) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DevKillTask(void *devser) {
|
static void DevKillTask(void *ds) {
|
||||||
if(devser != NULL){
|
DevSer *devser = ds;
|
||||||
DevKill(devser);
|
|
||||||
}
|
if (devser->stopTask) {
|
||||||
|
free(devser);
|
||||||
|
} else {
|
||||||
|
devser->stopTask = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DevAction *DevNextAction(DevSer *devser) {
|
DevAction *DevNextAction(DevSer *devser) {
|
||||||
@ -83,8 +87,12 @@ DevAction *DevNextAction(DevSer *devser) {
|
|||||||
if (header->followingAction == NULL) {
|
if (header->followingAction == NULL) {
|
||||||
if (now >= header->timeDue) {
|
if (now >= header->timeDue) {
|
||||||
header->followingAction = header->actions;
|
header->followingAction = header->actions;
|
||||||
header->timeDue = (floor(now / header->interval) + 1)
|
if (header->interval <= 0) {
|
||||||
* header->interval;
|
header->timeDue = now;
|
||||||
|
} else {
|
||||||
|
header->timeDue = (floor(now / header->interval) + 1)
|
||||||
|
* header->interval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (header->followingAction != NULL) {
|
if (header->followingAction != NULL) {
|
||||||
@ -110,7 +118,7 @@ int DevQueueTask(void *ds) {
|
|||||||
char *replyData;
|
char *replyData;
|
||||||
|
|
||||||
if (devser->steps == 0) return 1;
|
if (devser->steps == 0) return 1;
|
||||||
if (devser->killMe) {
|
if (devser->stopTask) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
action = devser->current;
|
action = devser->current;
|
||||||
@ -128,9 +136,9 @@ int DevQueueTask(void *ds) {
|
|||||||
devser->steps--;
|
devser->steps--;
|
||||||
}
|
}
|
||||||
if(status == AsconFailure){
|
if(status == AsconFailure){
|
||||||
replyData = devser->errmsg->text;
|
replyData = devser->errmsg->text;
|
||||||
} else {
|
} else {
|
||||||
replyData = AsconRead(devser->asyncConn);
|
replyData = AsconRead(devser->asyncConn);
|
||||||
}
|
}
|
||||||
sendData = action->hdl(action->data, replyData);
|
sendData = action->hdl(action->data, replyData);
|
||||||
if (sendData != NULL) {
|
if (sendData != NULL) {
|
||||||
@ -163,7 +171,7 @@ DevSer *DevMake(SConnection *con, int argc, char *argv[]) {
|
|||||||
devser->killCurrent = 0;
|
devser->killCurrent = 0;
|
||||||
devser->actions = NULL;
|
devser->actions = NULL;
|
||||||
devser->headers = NULL;
|
devser->headers = NULL;
|
||||||
devser->killMe = 0;
|
devser->stopTask = 0;
|
||||||
devser->steps = -1; /* no debugging by default */
|
devser->steps = -1; /* no debugging by default */
|
||||||
TaskRegister(pServ->pTasker, DevQueueTask, NULL, DevKillTask, devser, 0);
|
TaskRegister(pServ->pTasker, DevQueueTask, NULL, DevKillTask, devser, 0);
|
||||||
return devser;
|
return devser;
|
||||||
@ -200,7 +208,11 @@ void DevKill(DevSer *devser) {
|
|||||||
DevFreeActionList(victim->actions);
|
DevFreeActionList(victim->actions);
|
||||||
free(victim);
|
free(victim);
|
||||||
}
|
}
|
||||||
devser->killMe = 1;
|
if (devser->stopTask) {
|
||||||
|
free(devser);
|
||||||
|
} else {
|
||||||
|
devser->stopTask = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevQueue(DevSer *devser, void *actionData, DevPrio prio,
|
void DevQueue(DevSer *devser, void *actionData, DevPrio prio,
|
||||||
@ -213,7 +225,7 @@ void DevQueue(DevSer *devser, void *actionData, DevPrio prio,
|
|||||||
if (prio >= NumberOfPRIO) prio = NumberOfPRIO - 1;
|
if (prio >= NumberOfPRIO) prio = NumberOfPRIO - 1;
|
||||||
ptr2Last = &devser->actions;
|
ptr2Last = &devser->actions;
|
||||||
for (action = devser->actions; action != NULL && action->prio >= prio; action = action->next) {
|
for (action = devser->actions; action != NULL && action->prio >= prio; action = action->next) {
|
||||||
if (matchFunc(actionData, action->data) && action->hdl == hdl) {
|
if (action->hdl == hdl && matchFunc(actionData, action->data)) {
|
||||||
return; /* there is already an identic action */
|
return; /* there is already an identic action */
|
||||||
}
|
}
|
||||||
ptr2Last = &action->next;
|
ptr2Last = &action->next;
|
||||||
@ -234,11 +246,15 @@ int DevUnschedule(DevSer *devser, void *actionData,
|
|||||||
for (header = devser->headers; header != NULL; header = header->next) {
|
for (header = devser->headers; header != NULL; header = header->next) {
|
||||||
ptr2Last = &header->actions;
|
ptr2Last = &header->actions;
|
||||||
for (action = header->actions; action != NULL; action = *ptr2Last) {
|
for (action = header->actions; action != NULL; action = *ptr2Last) {
|
||||||
if (matchFunc(actionData, action->data) && action->hdl == hdl) {
|
if (action->hdl == hdl && matchFunc(actionData, action->data)) {
|
||||||
if (action == header->followingAction) {
|
if (action == header->followingAction) {
|
||||||
/* advance followingAction if equal*/
|
/* advance followingAction if equal*/
|
||||||
header->followingAction = action->next;
|
header->followingAction = action->next;
|
||||||
}
|
}
|
||||||
|
if (action == devser->current) {
|
||||||
|
devser->current = NULL;
|
||||||
|
devser->killCurrent = 0; /* should already be 0 */
|
||||||
|
}
|
||||||
cnt++;
|
cnt++;
|
||||||
/* remove from list */
|
/* remove from list */
|
||||||
*ptr2Last = action->next;
|
*ptr2Last = action->next;
|
||||||
@ -252,20 +268,21 @@ int DevUnschedule(DevSer *devser, void *actionData,
|
|||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevSchedule(DevSer *devser, void *actionData,
|
int DevSchedule(DevSer *devser, void *actionData,
|
||||||
DevPrio prio, double interval,
|
DevPrio prio, double interval,
|
||||||
DevActionHandler hdl, DevActionMatch *matchFunc,
|
DevActionHandler hdl, DevActionMatch *matchFunc,
|
||||||
DevKillActionData *killFunc) {
|
DevKillActionData *killFunc) {
|
||||||
SchedHeader *header = NULL;
|
SchedHeader *header = NULL;
|
||||||
SchedHeader **ptr2LastHeader = NULL;
|
SchedHeader **ptr2LastHeader = NULL;
|
||||||
SchedHeader *newHeader;
|
SchedHeader *newHeader;
|
||||||
DevAction *action = NULL;
|
DevAction *action = NULL;
|
||||||
DevAction **ptr2Last = NULL;
|
DevAction **ptr2Last = NULL;
|
||||||
DevAction *newAction;
|
DevAction *newAction;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (prio <= NullPRIO) prio = NullPRIO + 1;
|
if (prio <= NullPRIO) prio = NullPRIO + 1;
|
||||||
if (prio >= NumberOfPRIO) prio = NumberOfPRIO - 1;
|
if (prio >= NumberOfPRIO) prio = NumberOfPRIO - 1;
|
||||||
DevUnschedule(devser, actionData, hdl, matchFunc);
|
ret = DevUnschedule(devser, actionData, hdl, matchFunc);
|
||||||
|
|
||||||
newAction = DevNewAction(actionData, hdl, killFunc, prio);
|
newAction = DevNewAction(actionData, hdl, killFunc, prio);
|
||||||
/* find matching header */
|
/* find matching header */
|
||||||
@ -279,7 +296,7 @@ void DevSchedule(DevSer *devser, void *actionData,
|
|||||||
}
|
}
|
||||||
*ptr2Last = newAction;
|
*ptr2Last = newAction;
|
||||||
assert(newAction->next == NULL);
|
assert(newAction->next == NULL);
|
||||||
return;
|
return ret;
|
||||||
} else if (header->prio < newAction->prio ||
|
} else if (header->prio < newAction->prio ||
|
||||||
(header->prio == newAction->prio
|
(header->prio == newAction->prio
|
||||||
&& header->interval > interval)) {
|
&& header->interval > interval)) {
|
||||||
@ -304,5 +321,38 @@ void DevSchedule(DevSer *devser, void *actionData,
|
|||||||
newHeader->next = header;
|
newHeader->next = header;
|
||||||
newHeader->timeDue = DoubleTime() + interval;
|
newHeader->timeDue = DoubleTime() + interval;
|
||||||
*ptr2LastHeader = newHeader;
|
*ptr2LastHeader = newHeader;
|
||||||
return;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DevRemoveAction(DevSer *devser, void *actionData) {
|
||||||
|
SchedHeader *header = NULL;
|
||||||
|
DevAction **ptr2Last = NULL;
|
||||||
|
DevAction *action = NULL;
|
||||||
|
int cnt=0;
|
||||||
|
|
||||||
|
/* Remove current action, if matched. If a reply is pending, the next action will
|
||||||
|
get the reply. But as in the inital state no reply is expected, this should not harm. */
|
||||||
|
action = devser->current;
|
||||||
|
if (action != NULL && actionData == action->data) {
|
||||||
|
if (devser->killCurrent) {
|
||||||
|
if (action->kill != NULL) action->kill(action->data);
|
||||||
|
devser->killCurrent = 0;
|
||||||
|
free(action);
|
||||||
|
}
|
||||||
|
devser->current = NULL;
|
||||||
|
}
|
||||||
|
/* remove from queue */
|
||||||
|
ptr2Last = &devser->actions;
|
||||||
|
for (action = devser->actions; action != NULL; action = action->next) {
|
||||||
|
if (actionData == action->data) {
|
||||||
|
cnt++;
|
||||||
|
/* remove from list */
|
||||||
|
*ptr2Last = action->next;
|
||||||
|
if (action->kill != NULL) action->kill(action->data);
|
||||||
|
free(action);
|
||||||
|
} else {
|
||||||
|
ptr2Last = &action->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cnt++;
|
||||||
}
|
}
|
||||||
|
28
devser.h
28
devser.h
@ -15,12 +15,12 @@ typedef struct DevSer DevSer;
|
|||||||
*/
|
*/
|
||||||
typedef char *DevActionHandler(void *actionData, char *lastReply);
|
typedef char *DevActionHandler(void *actionData, char *lastReply);
|
||||||
|
|
||||||
/** \brief Check if two actions match
|
/** \brief Check if an action matches the call data
|
||||||
* \param actionData1 the first action data
|
* \param callData the callers data
|
||||||
* \param actionData2 the second action data
|
* \param actionData the action data
|
||||||
* \return 1 on a match, 0 on no match
|
* \return 1 on a match, 0 on no match
|
||||||
*/
|
*/
|
||||||
typedef int DevActionMatch(void *actionData1, void *actionData2);
|
typedef int DevActionMatch(void *callData, void *actionData);
|
||||||
|
|
||||||
/** \brief Kill ActionData
|
/** \brief Kill ActionData
|
||||||
* \param actionData action data
|
* \param actionData action data
|
||||||
@ -48,7 +48,9 @@ DevSer *DevMake(SConnection *con, int argc, char *argv[]);
|
|||||||
*/
|
*/
|
||||||
void DevDebugMode(DevSer *devser, int steps);
|
void DevDebugMode(DevSer *devser, int steps);
|
||||||
|
|
||||||
/** \brief Kill the device serializer and its async connection.
|
/** \brief Kill the contents of the device serializer and its async connection.
|
||||||
|
*
|
||||||
|
* The data structure itself is killed at some time later
|
||||||
* \param devser the device serializer
|
* \param devser the device serializer
|
||||||
*/
|
*/
|
||||||
void DevKill(DevSer *devser);
|
void DevKill(DevSer *devser);
|
||||||
@ -79,24 +81,32 @@ void DevQueue(DevSer *devser, void *actionData, DevPrio prio,
|
|||||||
* \param prio the priority
|
* \param prio the priority
|
||||||
* \param interval the interval in seconds (0 is allowed)
|
* \param interval the interval in seconds (0 is allowed)
|
||||||
* \param hdl the action handler
|
* \param hdl the action handler
|
||||||
* \param matchFunc the match function
|
* \param matchFunc the match function (callData must be of the same type as actionData)
|
||||||
* \param killFunc the action data kill function (called from DevKill and
|
* \param killFunc the action data kill function (called from DevKill and
|
||||||
* from DevUnschedule) or NULL if no kill function is needed.
|
* from DevUnschedule) or NULL if no kill function is needed.
|
||||||
|
* \return 0 when this was a new action, > 0 when an action was overwritten
|
||||||
*/
|
*/
|
||||||
void DevSchedule(DevSer *devser, void *actionData,
|
int DevSchedule(DevSer *devser, void *actionData,
|
||||||
DevPrio prio, double interval,
|
DevPrio prio, double interval,
|
||||||
DevActionHandler hdl, DevActionMatch *matchFunc,
|
DevActionHandler hdl, DevActionMatch *matchFunc,
|
||||||
DevKillActionData *killFunc);
|
DevKillActionData *killFunc);
|
||||||
|
|
||||||
/** \brief Unschedule matching actions
|
/** \brief Unschedule matching actions
|
||||||
* \param devser the device serializer
|
* \param devser the device serializer
|
||||||
* \param actionData the action data to be compared for a match
|
* \param callData the callers data to be as first argument of the match function
|
||||||
* \param hdl the action handler
|
* \param hdl the action handler
|
||||||
* \param matchFunc the match function
|
* \param matchFunc the match function (callData does not need to have the same type as actionData)
|
||||||
|
* \return the number of unscheduled actions
|
||||||
*/
|
*/
|
||||||
int DevUnschedule(DevSer *devser, void *actionData,
|
int DevUnschedule(DevSer *devser, void *actionData,
|
||||||
DevActionHandler hdl, DevActionMatch *matchFunc);
|
DevActionHandler hdl, DevActionMatch *matchFunc);
|
||||||
|
|
||||||
|
/** \brief remove action from the serializer
|
||||||
|
* \param devser the device serializer
|
||||||
|
* \param actionData the action data to be compared for a match
|
||||||
|
*/
|
||||||
|
int DevRemoveAction(DevSer *devser, void *actionData);
|
||||||
|
|
||||||
/** \brief Convert integer priority to text
|
/** \brief Convert integer priority to text
|
||||||
* \param prio
|
* \param prio
|
||||||
* \return text
|
* \return text
|
||||||
|
1
ofac.c
1
ofac.c
@ -444,6 +444,7 @@
|
|||||||
INIT(InitializerInit);
|
INIT(InitializerInit);
|
||||||
INIT(SaveHdbInit); /* must be after InitializerInit */
|
INIT(SaveHdbInit); /* must be after InitializerInit */
|
||||||
INIT(SctInit);
|
INIT(SctInit);
|
||||||
|
INIT(SctDriveInit);
|
||||||
INIT(LogReaderInit);
|
INIT(LogReaderInit);
|
||||||
INIT(LogSetupInit);
|
INIT(LogSetupInit);
|
||||||
INIT(StatusFileInit);
|
INIT(StatusFileInit);
|
||||||
|
251
scriptcontext.c
251
scriptcontext.c
@ -13,6 +13,7 @@
|
|||||||
#include "devser.h"
|
#include "devser.h"
|
||||||
#include "ascon.h"
|
#include "ascon.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "scriptcontext.h"
|
||||||
|
|
||||||
|
|
||||||
#define MAX_HDB_PATH 1024
|
#define MAX_HDB_PATH 1024
|
||||||
@ -30,20 +31,20 @@ typedef struct ScriptContext {
|
|||||||
ContextItem *base;
|
ContextItem *base;
|
||||||
} ScriptContext;
|
} ScriptContext;
|
||||||
|
|
||||||
typedef struct SctController {
|
struct SctController {
|
||||||
DevSer *devser;
|
DevSer *devser;
|
||||||
Hdb *node; /* the controller node */
|
Hdb *node; /* the controller node */
|
||||||
SCStore *conn;
|
SCStore *conn;
|
||||||
int verbose;
|
int verbose;
|
||||||
} SctController;
|
};
|
||||||
|
|
||||||
|
/* action data and write callback data */
|
||||||
typedef struct SctData {
|
typedef struct SctData {
|
||||||
int writable;
|
|
||||||
char *name;
|
char *name;
|
||||||
SctController *controller;
|
SctController *controller;
|
||||||
SCStore *conCtx;
|
SCStore *conCtx;
|
||||||
int answered;
|
int answered;
|
||||||
Hdb *node; /* back link used by SctMatchWrite/SctMatchPoll */
|
Hdb *node;
|
||||||
} SctData;
|
} SctData;
|
||||||
|
|
||||||
static ScriptContext *sct = NULL;
|
static ScriptContext *sct = NULL;
|
||||||
@ -206,9 +207,13 @@ int SctCommand(SConnection *con, SicsInterp *sics, void *object,
|
|||||||
}
|
}
|
||||||
SCWrite(con, val, eValue);
|
SCWrite(con, val, eValue);
|
||||||
} else { /* set case */
|
} else { /* set case */
|
||||||
val = Arg2Tcl(argc-2, argv+2, value, sizeof value);
|
if (argc == 3) {
|
||||||
SetProp(node, cNode, argv[1], val);
|
SetProp(node, cNode, argv[1], argv[2]);
|
||||||
if (val != NULL && val != value) free(val);
|
} else {
|
||||||
|
val = Arg2Tcl(argc-2, argv+2, value, sizeof value);
|
||||||
|
SetProp(node, cNode, argv[1], val);
|
||||||
|
if (val != NULL && val != value) free(val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -289,10 +294,6 @@ static char *SctActionHandler(void *actionData, char *lastReply) {
|
|||||||
if (currentCon && ! data->answered) {
|
if (currentCon && ! data->answered) {
|
||||||
SCWrite(con, "o.k.", eValue);
|
SCWrite(con, "o.k.", eValue);
|
||||||
}
|
}
|
||||||
if (data->conCtx != NULL) {
|
|
||||||
SCStoreFree(data->conCtx);
|
|
||||||
data->conCtx = NULL;
|
|
||||||
}
|
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
SetProp(node, controller->node, "state", state);
|
SetProp(node, controller->node, "state", state);
|
||||||
@ -301,18 +302,26 @@ static char *SctActionHandler(void *actionData, char *lastReply) {
|
|||||||
if (controller->verbose) {
|
if (controller->verbose) {
|
||||||
SCPrintf(con, eWarning, "send : %s", send);
|
SCPrintf(con, eWarning, "send : %s", send);
|
||||||
}
|
}
|
||||||
goto quit;
|
if (currentCon) {
|
||||||
|
SCStorePop(currentCon);
|
||||||
|
} else {
|
||||||
|
SCStorePop(controller->conn);
|
||||||
|
}
|
||||||
|
return send;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SCPrintf(con, eError, "ERROR: too many quick scripts chained");
|
SCPrintf(con, eError, "ERROR: too many quick scripts chained");
|
||||||
finish:
|
finish:
|
||||||
SetProp(node, controller->node, "state", "idle");
|
SetProp(node, controller->node, "state", "idle");
|
||||||
quit:
|
|
||||||
if (currentCon) {
|
if (currentCon) {
|
||||||
SCStorePop(currentCon);
|
SCStorePop(currentCon);
|
||||||
} else {
|
} else {
|
||||||
SCStorePop(controller->conn);
|
SCStorePop(controller->conn);
|
||||||
}
|
}
|
||||||
|
if (data->conCtx != NULL) {
|
||||||
|
SCStoreFree(data->conCtx);
|
||||||
|
data->conCtx = NULL;
|
||||||
|
}
|
||||||
return send;
|
return send;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,6 +337,13 @@ static char *SctWriteHandler(void *actionData, char *lastReply) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int SctMatchNode(void *vNode, void *vData) {
|
||||||
|
Hdb *node = vNode;
|
||||||
|
SctData *d = vData;
|
||||||
|
|
||||||
|
return node == d->node;
|
||||||
|
}
|
||||||
|
|
||||||
static hdbCallbackReturn SctMainCallback(Hdb *node, void *userData,
|
static hdbCallbackReturn SctMainCallback(Hdb *node, void *userData,
|
||||||
hdbMessage *msg) {
|
hdbMessage *msg) {
|
||||||
SctController *controller = userData;
|
SctController *controller = userData;
|
||||||
@ -356,6 +372,8 @@ static hdbCallbackReturn SctMainCallback(Hdb *node, void *userData,
|
|||||||
}
|
}
|
||||||
km = GetHdbKillNodeMessage(msg);
|
km = GetHdbKillNodeMessage(msg);
|
||||||
if (km != NULL) {
|
if (km != NULL) {
|
||||||
|
/* unschedule all actions related to this node */
|
||||||
|
DevUnschedule(controller->devser, node, SctActionHandler, SctMatchNode);
|
||||||
CleanStack(node);
|
CleanStack(node);
|
||||||
return hdbContinue;
|
return hdbContinue;
|
||||||
}
|
}
|
||||||
@ -378,6 +396,7 @@ static hdbCallbackReturn SctActionCallback(Hdb *node, void *userData,
|
|||||||
hdbDataSearch *dsm;
|
hdbDataSearch *dsm;
|
||||||
hdbDataMessage *mm;
|
hdbDataMessage *mm;
|
||||||
hdbPtrMessage *pm;
|
hdbPtrMessage *pm;
|
||||||
|
hdbMessage *km;
|
||||||
SctData *data = userData;
|
SctData *data = userData;
|
||||||
Hdb *target;
|
Hdb *target;
|
||||||
char *script;
|
char *script;
|
||||||
@ -410,7 +429,7 @@ static hdbCallbackReturn SctActionCallback(Hdb *node, void *userData,
|
|||||||
}
|
}
|
||||||
|
|
||||||
mm = GetHdbSetMessage(msg);
|
mm = GetHdbSetMessage(msg);
|
||||||
if (mm != NULL && data->writable) {
|
if (mm != NULL) {
|
||||||
con = mm->callData;
|
con = mm->callData;
|
||||||
|
|
||||||
/* set target value */
|
/* set target value */
|
||||||
@ -432,7 +451,10 @@ static hdbCallbackReturn SctActionCallback(Hdb *node, void *userData,
|
|||||||
writeprio = GetProp(node, data->controller->node, "writeprio");
|
writeprio = GetProp(node, data->controller->node, "writeprio");
|
||||||
if (writeprio != NULL) {
|
if (writeprio != NULL) {
|
||||||
prio = DevText2Prio(writeprio);
|
prio = DevText2Prio(writeprio);
|
||||||
if (prio < 0) prio = WritePRIO;
|
if (prio == NullPRIO) {
|
||||||
|
SCPrintf(con, eError, "ERROR: unknown priority: %s", writeprio);
|
||||||
|
prio = WritePRIO;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
prio = WritePRIO;
|
prio = WritePRIO;
|
||||||
}
|
}
|
||||||
@ -449,6 +471,7 @@ static hdbCallbackReturn SctActionCallback(Hdb *node, void *userData,
|
|||||||
data->answered = 0;
|
data->answered = 0;
|
||||||
DevQueue(data->controller->devser, data, prio,
|
DevQueue(data->controller->devser, data, prio,
|
||||||
SctWriteHandler, SctMatch, NULL);
|
SctWriteHandler, SctMatch, NULL);
|
||||||
|
/* no kill function in DevQueue: data is owned by the node (callback list) */
|
||||||
return hdbContinue;
|
return hdbContinue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,37 +492,53 @@ static hdbCallbackReturn SctActionCallback(Hdb *node, void *userData,
|
|||||||
return hdbContinue;
|
return hdbContinue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *ParText(Hdb *cmdNode, char *name) {
|
static char *ParText(Hdb *cmdNode, char *name,
|
||||||
|
int nPar, char *defaultValue) {
|
||||||
Hdb *par;
|
Hdb *par;
|
||||||
|
|
||||||
par = GetHipadabaNode(cmdNode, name);
|
for (par = cmdNode->child; nPar > 0 && par != NULL;
|
||||||
if (par && par->value.dataType == HIPTEXT) {
|
par = par->next, nPar--) {
|
||||||
return par->value.v.text;
|
if (strcasecmp(par->name, name) == 0) {
|
||||||
}
|
if (par->value.dataType == HIPTEXT) {
|
||||||
return "<undefined>";
|
return par->value.v.text;
|
||||||
}
|
}
|
||||||
|
|
||||||
static double ParValue(Hdb *cmdNode, char *name) {
|
|
||||||
Hdb *par;
|
|
||||||
|
|
||||||
par = GetHipadabaNode(cmdNode, name);
|
|
||||||
if (par) {
|
|
||||||
switch (par->value.dataType) {
|
|
||||||
case HIPINT: return par->value.v.intValue;
|
|
||||||
case HIPFLOAT: return par->value.v.doubleValue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -999;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SctKillData(void *d) {
|
static double ParValue(Hdb *cmdNode, char *name,
|
||||||
|
int nPar, double defaultValue) {
|
||||||
|
Hdb *par;
|
||||||
|
|
||||||
|
for (par = cmdNode->child; nPar > 0 && par != NULL;
|
||||||
|
par = par->next, nPar--) {
|
||||||
|
if (strcasecmp(par->name, name) == 0) {
|
||||||
|
switch (par->value.dataType) {
|
||||||
|
case HIPINT: return par->value.v.intValue;
|
||||||
|
case HIPFLOAT: return par->value.v.doubleValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SctKillData(void *d) {
|
||||||
SctData *data = d;
|
SctData *data = d;
|
||||||
|
|
||||||
if (data->name) free(data->name);
|
if (data->name) free(data->name);
|
||||||
if (data->conCtx) SCStoreFree(data->conCtx);
|
if (data->conCtx) SCStoreFree(data->conCtx);
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SctAddPollNode(SctController *controller, Hdb *node, double interval,
|
static void SctKillCBData(void *d) {
|
||||||
|
SctData *data = d;
|
||||||
|
|
||||||
|
DevRemoveAction(data->controller->devser, data);
|
||||||
|
SctKillData(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SctAddPollNode(SctController *controller, Hdb *node, double interval,
|
||||||
DevPrio prio, char *action) {
|
DevPrio prio, char *action) {
|
||||||
SctData *data;
|
SctData *data;
|
||||||
hdbCallback *cb;
|
hdbCallback *cb;
|
||||||
@ -508,22 +547,18 @@ void SctAddPollNode(SctController *controller, Hdb *node, double interval,
|
|||||||
cb = MakeHipadabaCallback(SctMainCallback, controller, NULL);
|
cb = MakeHipadabaCallback(SctMainCallback, controller, NULL);
|
||||||
assert(cb);
|
assert(cb);
|
||||||
AppendHipadabaCallback(node, cb);
|
AppendHipadabaCallback(node, cb);
|
||||||
|
SetHdbProperty(node,"geterror","Not read yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
actionCallback.name = action;
|
data = calloc(1, sizeof(*data));
|
||||||
data = FindHdbCallbackData(node, &actionCallback);
|
assert(data);
|
||||||
if (data == NULL) {
|
data->controller = controller;
|
||||||
data = calloc(1, sizeof(*data));
|
data->node = node;
|
||||||
assert(data);
|
data->conCtx = NULL;
|
||||||
data->controller = controller;
|
data->name = strdup(action);
|
||||||
data->node = node;
|
|
||||||
data->writable = 0;
|
|
||||||
data->conCtx = NULL;
|
|
||||||
data->name = strdup(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
DevSchedule(controller->devser, data, prio, interval,
|
return DevSchedule(controller->devser, data, prio, interval,
|
||||||
SctActionHandler, SctMatch, NULL);
|
SctActionHandler, SctMatch, SctKillData);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,6 +570,7 @@ static int SctPollCmd(pSICSOBJ ccmd, SConnection *con,
|
|||||||
char *path;
|
char *path;
|
||||||
DevPrio prio;
|
DevPrio prio;
|
||||||
char *action;
|
char *action;
|
||||||
|
char *prioText;
|
||||||
|
|
||||||
if(nPar < 1){
|
if(nPar < 1){
|
||||||
SCPrintf(con,eError,
|
SCPrintf(con,eError,
|
||||||
@ -543,21 +579,63 @@ static int SctPollCmd(pSICSOBJ ccmd, SConnection *con,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
controller = ccmd->pPrivate;
|
controller = ccmd->pPrivate;
|
||||||
path = ParText(cmdNode, "node");
|
path = ParText(cmdNode, "node", nPar, "");
|
||||||
node = FindHdbNode(NULL, path, con);
|
node = FindHdbNode(NULL, path, con);
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
SCPrintf(con, eError, "ERROR: %s not found", path);
|
SCPrintf(con, eError, "ERROR: %s not found", path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
SetHdbProperty(node,"geterror","Not read yet");
|
interval = ParValue(cmdNode, "interval", nPar, 5);
|
||||||
interval = ParValue(cmdNode, "interval");
|
prioText = ParText(cmdNode, "prio", nPar, "read");
|
||||||
prio = DevText2Prio(ParText(cmdNode, "prio"));
|
prio = DevText2Prio(prioText);
|
||||||
action = ParText(cmdNode, "action");
|
if (prio == NullPRIO) {
|
||||||
|
SCPrintf(con,eError, "ERROR: unknown priority: %s", prioText);
|
||||||
SctAddPollNode(controller, node, interval, prio, action);
|
return 0;
|
||||||
|
}
|
||||||
|
action = ParText(cmdNode, "action", nPar, "read");
|
||||||
|
|
||||||
|
if (SctAddPollNode(controller, node, interval, prio, action) > 0) {
|
||||||
|
SCPrintf(con, eValue,
|
||||||
|
"%s poll on %s changed to %g sec, %s prio",
|
||||||
|
action, path, interval, prioText);
|
||||||
|
} else {
|
||||||
|
SCPrintf(con, eValue,
|
||||||
|
"%s poll registered on %s (%g sec, %s prio)",
|
||||||
|
action, path, interval, prioText);
|
||||||
|
}
|
||||||
sct->base->node = node;
|
sct->base->node = node;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SctUnpollCmd(pSICSOBJ ccmd, SConnection *con,
|
||||||
|
Hdb *cmdNode, Hdb *par[], int nPar) {
|
||||||
|
SctController *controller;
|
||||||
|
double interval;
|
||||||
|
char *path;
|
||||||
|
DevPrio prio;
|
||||||
|
char *prioText;
|
||||||
|
SctData data;
|
||||||
|
|
||||||
|
if(nPar < 1){
|
||||||
|
SCPrintf(con,eError,
|
||||||
|
"ERROR: should be: %s poll <node> (<action>)",
|
||||||
|
ccmd->objectNode->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
controller = ccmd->pPrivate;
|
||||||
|
path = ParText(cmdNode, "node", nPar, "");
|
||||||
|
data.node = FindHdbNode(NULL, path, con);
|
||||||
|
if (data.node == NULL) {
|
||||||
|
SCPrintf(con, eError, "ERROR: %s not found", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
data.name = ParText(cmdNode, "action", nPar, "read");
|
||||||
|
if (DevUnschedule(controller->devser, &data, SctActionHandler, SctMatch) == 0) {
|
||||||
|
SCPrintf(con, eValue,
|
||||||
|
"%s poll not found on %s", data.name, path);
|
||||||
|
} else {
|
||||||
|
SCSendOK(con);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,7 +653,7 @@ static int SctConnectCmd(pSICSOBJ ccmd, SConnection *con,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
controller = ccmd->pPrivate;
|
controller = ccmd->pPrivate;
|
||||||
path = ParText(cmdNode, "node");
|
path = ParText(cmdNode, "node", nPar, "");
|
||||||
node = FindHdbNode(NULL, path, con);
|
node = FindHdbNode(NULL, path, con);
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
SCPrintf(con, eError, "ERROR: %s not found", path);
|
SCPrintf(con, eError, "ERROR: %s not found", path);
|
||||||
@ -601,7 +679,7 @@ int SctAddWriteNode(SctController *controller, Hdb *node) {
|
|||||||
AppendHipadabaCallback(node, cb);
|
AppendHipadabaCallback(node, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
actionCallback.name = strdup("write");
|
actionCallback.name = "write"; /* local, so no strdup here */
|
||||||
data = FindHdbCallbackData(node, &actionCallback);
|
data = FindHdbCallbackData(node, &actionCallback);
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -610,11 +688,10 @@ int SctAddWriteNode(SctController *controller, Hdb *node) {
|
|||||||
assert(data);
|
assert(data);
|
||||||
data->controller = controller;
|
data->controller = controller;
|
||||||
data->node = node;
|
data->node = node;
|
||||||
data->writable = 1;
|
|
||||||
data->conCtx = NULL;
|
data->conCtx = NULL;
|
||||||
data->name = strdup("write");
|
data->name = strdup("write");
|
||||||
|
|
||||||
cb = MakeHipadabaCallback(SctActionCallback, data, SctKillData);
|
cb = MakeHipadabaCallback(SctActionCallback, data, SctKillCBData);
|
||||||
assert(cb);
|
assert(cb);
|
||||||
data->node = node;
|
data->node = node;
|
||||||
AppendHipadabaCallback(node, cb);
|
AppendHipadabaCallback(node, cb);
|
||||||
@ -635,7 +712,7 @@ static int SctWriteCmd(pSICSOBJ ccmd, SConnection *con,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
controller = ccmd->pPrivate;
|
controller = ccmd->pPrivate;
|
||||||
path = ParText(cmdNode, "node");
|
path = ParText(cmdNode, "node", nPar, "");
|
||||||
node = FindHdbNode(NULL, path, con);
|
node = FindHdbNode(NULL, path, con);
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
SCPrintf(con, eError, "ERROR: %s not found", path);
|
SCPrintf(con, eError, "ERROR: %s not found", path);
|
||||||
@ -647,12 +724,13 @@ static int SctWriteCmd(pSICSOBJ ccmd, SConnection *con,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SCSendOK(con);
|
||||||
sct->base->node = node;
|
sct->base->node = node;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SctData *SctQueueNode(SctController *controller, Hdb *node,
|
void SctQueueNode(SctController *controller, Hdb *node,
|
||||||
DevPrio prio, char *action) {
|
DevPrio prio, char *action, SConnection *con) {
|
||||||
SctData *data;
|
SctData *data;
|
||||||
hdbCallback *cb;
|
hdbCallback *cb;
|
||||||
|
|
||||||
@ -666,13 +744,15 @@ SctData *SctQueueNode(SctController *controller, Hdb *node,
|
|||||||
assert(data);
|
assert(data);
|
||||||
data->controller = controller;
|
data->controller = controller;
|
||||||
data->node = node;
|
data->node = node;
|
||||||
data->writable = 0;
|
|
||||||
data->name = strdup(action);
|
data->name = strdup(action);
|
||||||
data->conCtx = NULL;
|
data->conCtx = NULL;
|
||||||
|
|
||||||
DevQueue(data->controller->devser, data, prio,
|
DevQueue(data->controller->devser, data, prio,
|
||||||
SctWriteHandler, SctMatch, SctKillData);
|
SctWriteHandler, SctMatch, SctKillData);
|
||||||
return data;
|
if (con != NULL) {
|
||||||
|
data->conCtx = SCSave(con, NULL);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int SctQueueCmd(pSICSOBJ ccmd, SConnection *con,
|
static int SctQueueCmd(pSICSOBJ ccmd, SConnection *con,
|
||||||
@ -684,24 +764,30 @@ static int SctQueueCmd(pSICSOBJ ccmd, SConnection *con,
|
|||||||
char *action;
|
char *action;
|
||||||
DevPrio prio;
|
DevPrio prio;
|
||||||
SctData *data;
|
SctData *data;
|
||||||
|
char *prioText;
|
||||||
|
|
||||||
if(nPar < 2){
|
if(nPar < 2){
|
||||||
SCPrintf(con,eError, "ERROR: should be: %s queue <node> <prio> <action>",
|
SCPrintf(con,eError,
|
||||||
|
"ERROR: should be: %s queue <node> <prio> <action>",
|
||||||
ccmd->objectNode->name);
|
ccmd->objectNode->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
controller = ccmd->pPrivate;
|
controller = ccmd->pPrivate;
|
||||||
path = ParText(cmdNode, "node");
|
path = ParText(cmdNode, "node", nPar, "");
|
||||||
node = FindHdbNode(NULL, path, con);
|
node = FindHdbNode(NULL, path, con);
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
SCPrintf(con, eError, "ERROR: %s not found", path);
|
SCPrintf(con, eError, "ERROR: %s not found", path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
prio = DevText2Prio(ParText(cmdNode, "prio"));
|
prioText = ParText(cmdNode, "prio", nPar, "write");
|
||||||
action = ParText(cmdNode, "action");
|
prio = DevText2Prio(prioText);
|
||||||
|
if (prio == NullPRIO) {
|
||||||
|
SCPrintf(con,eError, "ERROR: unknown priority: %s", prioText);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
action = ParText(cmdNode, "action", nPar, "write");
|
||||||
|
|
||||||
data = SctQueueNode(controller, node, prio, action);
|
SctQueueNode(controller, node, prio, action, con);
|
||||||
data->conCtx = SCSave(con, NULL);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,7 +851,7 @@ static int SctTransactCmd(pSICSOBJ ccmd, SConnection *con,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int SctQueueComCmd(pSICSOBJ ccmd, SConnection *con,
|
static int SctSendCmd(pSICSOBJ ccmd, SConnection *con,
|
||||||
Hdb *cmdNode, Hdb *par[], int nPar) {
|
Hdb *cmdNode, Hdb *par[], int nPar) {
|
||||||
pSctTransact st = NULL;
|
pSctTransact st = NULL;
|
||||||
SctController *c;
|
SctController *c;
|
||||||
@ -774,7 +860,7 @@ static int SctQueueComCmd(pSICSOBJ ccmd, SConnection *con,
|
|||||||
|
|
||||||
st = calloc(sizeof(SctTransact),1);
|
st = calloc(sizeof(SctTransact),1);
|
||||||
if(st == NULL){
|
if(st == NULL){
|
||||||
SCWrite(con,"ERROR: out of memory in SctTransactCommand", eError);
|
SCWrite(con,"ERROR: out of memory in SctSendCmd", eError);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
st->con = con;
|
st->con = con;
|
||||||
@ -812,10 +898,17 @@ static hdbCallbackReturn SctDebugCallback(Hdb *node, void *userData,
|
|||||||
|
|
||||||
static void SctKillController(void *c) {
|
static void SctKillController(void *c) {
|
||||||
SctController *controller = c;
|
SctController *controller = c;
|
||||||
|
SConnection *con;
|
||||||
|
|
||||||
CleanStack(controller->node);
|
CleanStack(controller->node);
|
||||||
RemoveSICSInternalCallback(controller);
|
RemoveSICSInternalCallback(controller);
|
||||||
/* devser is killed by task function */
|
if (controller->conn) {
|
||||||
|
con = SCLoad(controller->conn);
|
||||||
|
SCDeleteConnection(con);
|
||||||
|
SCStoreFree(controller->conn);
|
||||||
|
}
|
||||||
|
DevKill(controller->devser);
|
||||||
|
free(controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int SctMakeController(SConnection *con, SicsInterp *sics,
|
static int SctMakeController(SConnection *con, SicsInterp *sics,
|
||||||
@ -864,6 +957,11 @@ static int SctMakeController(SConnection *con, SicsInterp *sics,
|
|||||||
AddSICSHdbPar(cmd, "prio", usMugger, MakeHdbText("read"));
|
AddSICSHdbPar(cmd, "prio", usMugger, MakeHdbText("read"));
|
||||||
AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("read"));
|
AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("read"));
|
||||||
|
|
||||||
|
cmd = AddSICSHdbPar(controller->node,
|
||||||
|
"unpoll", usMugger, MakeSICSFunc(SctUnpollCmd));
|
||||||
|
AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText(""));
|
||||||
|
AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("read"));
|
||||||
|
|
||||||
cmd = AddSICSHdbPar(controller->node,
|
cmd = AddSICSHdbPar(controller->node,
|
||||||
"connect", usMugger, MakeSICSFunc(SctConnectCmd));
|
"connect", usMugger, MakeSICSFunc(SctConnectCmd));
|
||||||
AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText(""));
|
AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText(""));
|
||||||
@ -884,11 +982,11 @@ static int SctMakeController(SConnection *con, SicsInterp *sics,
|
|||||||
AddSICSHdbPar(cmd, "data", usMugger, MakeHdbText(""));
|
AddSICSHdbPar(cmd, "data", usMugger, MakeHdbText(""));
|
||||||
|
|
||||||
cmd = AddSICSHdbPar(controller->node,
|
cmd = AddSICSHdbPar(controller->node,
|
||||||
"queuecom", usMugger, MakeSICSFunc(SctQueueComCmd));
|
"send", usMugger, MakeSICSFunc(SctSendCmd));
|
||||||
AddSICSHdbPar(cmd, "data", usMugger, MakeHdbText(""));
|
AddSICSHdbPar(cmd, "data", usMugger, MakeHdbText(""));
|
||||||
|
|
||||||
|
|
||||||
par = AddSICSHdbPar(controller->node, "debug", usUser, MakeHdbInt(0));
|
par = AddSICSHdbPar(controller->node, "debug", usUser, MakeHdbInt(-1));
|
||||||
|
|
||||||
cb = MakeHipadabaCallback(SctDebugCallback, controller, NULL);
|
cb = MakeHipadabaCallback(SctDebugCallback, controller, NULL);
|
||||||
if (cb) AppendHipadabaCallback(par, cb);
|
if (cb) AppendHipadabaCallback(par, cb);
|
||||||
@ -918,10 +1016,6 @@ void SctKill(void *object) {
|
|||||||
sct = NULL;
|
sct = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* from sctdriveadapter.c */
|
|
||||||
int SctMakeDriveAdapter(SConnection *pCon, SicsInterp *pSics, void *object,
|
|
||||||
int argc, char *argv[]);
|
|
||||||
|
|
||||||
void SctInit(void) {
|
void SctInit(void) {
|
||||||
if (sct) return;
|
if (sct) return;
|
||||||
sct = calloc(1, sizeof(*sct));
|
sct = calloc(1, sizeof(*sct));
|
||||||
@ -931,5 +1025,4 @@ void SctInit(void) {
|
|||||||
sct->base = sct->nodes;
|
sct->base = sct->nodes;
|
||||||
AddCommand(pServ->pSics, "sct", SctCommand, SctKill, sct);
|
AddCommand(pServ->pSics, "sct", SctCommand, SctKill, sct);
|
||||||
AddCmd("makesctcontroller", SctMakeController);
|
AddCmd("makesctcontroller", SctMakeController);
|
||||||
AddCmd("makesctdrive", SctMakeDriveAdapter);
|
|
||||||
}
|
}
|
||||||
|
33
scriptcontext.h
Normal file
33
scriptcontext.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef SCRIPTCONTEXT_H
|
||||||
|
#define SCRIPTCONTEXT_H
|
||||||
|
|
||||||
|
#include "sics.h"
|
||||||
|
#include "devser.h"
|
||||||
|
|
||||||
|
/* \brief an sct controller
|
||||||
|
*/
|
||||||
|
typedef struct SctController SctController;
|
||||||
|
|
||||||
|
/** \brief queue node action to a controller
|
||||||
|
*
|
||||||
|
* \param controller the controller
|
||||||
|
* \param node the node
|
||||||
|
* \param prio the priority
|
||||||
|
* \param action the initial state
|
||||||
|
* \param con an optional connection to be used by the action scripts
|
||||||
|
*/
|
||||||
|
void SctQueueNode(SctController *controller, Hdb *node,
|
||||||
|
DevPrio prio, char *action, SConnection *con);
|
||||||
|
|
||||||
|
/** \brief call a script and configure the sct command to be used
|
||||||
|
* in connection with the given node and controller
|
||||||
|
*
|
||||||
|
* \param con the connection
|
||||||
|
* \param script a tcl script
|
||||||
|
* \param the node to which the sct command
|
||||||
|
* \return 0 when this was a new action, > 0 when an action was overwritten
|
||||||
|
*/
|
||||||
|
int SctCallInContext(SConnection *con, char *script, Hdb *node,
|
||||||
|
SctController *controller, char **resPtr);
|
||||||
|
|
||||||
|
#endif
|
@ -3,7 +3,7 @@
|
|||||||
* scriptcontext generic device model. This is a wrapper around
|
* scriptcontext generic device model. This is a wrapper around
|
||||||
* such a node which implements the drivable interface.
|
* such a node which implements the drivable interface.
|
||||||
*
|
*
|
||||||
* Soem cooperation from the node is required: It has to provide
|
* Some cooperation from the node is required: It has to provide
|
||||||
* certain properties the value of which define scripts which
|
* certain properties the value of which define scripts which
|
||||||
* have to be called at various stages. These are:
|
* have to be called at various stages. These are:
|
||||||
*
|
*
|
||||||
@ -21,13 +21,7 @@
|
|||||||
#include <tcl.h>
|
#include <tcl.h>
|
||||||
#include <macro.h>
|
#include <macro.h>
|
||||||
#include <sicsobj.h>
|
#include <sicsobj.h>
|
||||||
/*------------- Some things from scriptcontext.c ----------------*/
|
#include "scriptcontext.h"
|
||||||
typedef struct SctController SctController;
|
|
||||||
typedef struct SctData SctData;
|
|
||||||
SctData *SctQueueNode(SctController *controller, pHdb node,
|
|
||||||
DevPrio prio, char *action);
|
|
||||||
int SctCallInContext(SConnection *con, char *script, Hdb *node,
|
|
||||||
SctController *controller, char **resPtr);
|
|
||||||
/*---------------------------------------------------------------*/
|
/*---------------------------------------------------------------*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
pObjectDescriptor pDes;
|
pObjectDescriptor pDes;
|
||||||
@ -41,6 +35,7 @@ static void *SCTDRIVGetInterface(void *data, int iD){
|
|||||||
|
|
||||||
self = (pSctDrive)data;
|
self = (pSctDrive)data;
|
||||||
if(self != NULL && iD == DRIVEID){
|
if(self != NULL && iD == DRIVEID){
|
||||||
|
if (self->node == NULL) return NULL;
|
||||||
return self->pDriv;
|
return self->pDriv;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -53,14 +48,14 @@ static void *SCTDRIVGetInterface(void *data, int iD){
|
|||||||
------------------------------------------------------------------*/
|
------------------------------------------------------------------*/
|
||||||
static int SCTDRIVHalt(void *data) {
|
static int SCTDRIVHalt(void *data) {
|
||||||
pSctDrive self = NULL;
|
pSctDrive self = NULL;
|
||||||
|
char dummy[16];
|
||||||
|
|
||||||
self = (pSctDrive)data;
|
self = (pSctDrive)data;
|
||||||
SctQueueNode(self->c, self->node, HaltPRIO, "halt");
|
if (GetHdbProperty(self->node,"halt", dummy, sizeof dummy)) {
|
||||||
/*
|
SctQueueNode(self->c, self->node, HaltPRIO, "halt", NULL);
|
||||||
* SctQueueNode returns a dynamically allocated SctData
|
} else if (GetHdbProperty(self->node, "status", dummy, sizeof dummy)) {
|
||||||
* structure. I am not sure if this is not really a memory
|
SetHdbProperty(self->node, "status", "idle");
|
||||||
* leak
|
}
|
||||||
*/
|
|
||||||
return OKOK;
|
return OKOK;
|
||||||
}
|
}
|
||||||
/*----------------------------------------------------------------
|
/*----------------------------------------------------------------
|
||||||
@ -85,6 +80,7 @@ static int SCTDRIVCheckLimits(void *data, float val,
|
|||||||
self->node, self->c, &result);
|
self->node, self->c, &result);
|
||||||
if(status == 0){
|
if(status == 0){
|
||||||
strncpy(error,result,errlen);
|
strncpy(error,result,errlen);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@ -132,31 +128,34 @@ static int SCTDRIVCheckStatus(void *data, SConnection *pCon){
|
|||||||
|
|
||||||
self = (pSctDrive)data;
|
self = (pSctDrive)data;
|
||||||
|
|
||||||
if(GetHdbProperty(self->node,"checkstatus",script,1024)){
|
if(!GetHdbProperty(self->node,"checkstatus",script,1024)){
|
||||||
status = SctCallInContext(pCon,script, self->node,
|
if (!GetHdbProperty(self->node,"status",script,1024)){
|
||||||
self->c, &result);
|
SCWrite(pCon,
|
||||||
if(status == 1){
|
"ERROR: configuration problem: no checkstatus script!", eError);
|
||||||
if(strstr(result,"busy") != NULL){
|
return HWFault;
|
||||||
return HWBusy;
|
}
|
||||||
} else if(strstr(result,"posfault") != NULL){
|
result = script;
|
||||||
return HWPosFault;
|
|
||||||
} else if(strstr(result,"fault") != NULL){
|
|
||||||
return HWFault;
|
|
||||||
} else if(strstr(result,"idle") != NULL){
|
|
||||||
return HWIdle;
|
|
||||||
} else {
|
|
||||||
SCPrintf(pCon,eError,"ERROR: invalid status code %s returned from checkstatus script",
|
|
||||||
result);
|
|
||||||
return HWFault;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SCWrite(pCon,result, eError);
|
|
||||||
return HWFault;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
SCWrite(pCon,
|
status = SctCallInContext(pCon,script, self->node,
|
||||||
"ERROR: configuration problem: no checkstatus script!", eError);
|
self->c, &result);
|
||||||
return HWFault;
|
if (status == 0) {
|
||||||
|
SCWrite(pCon,result, eError);
|
||||||
|
return HWFault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(strstr(result,"busy") != NULL){
|
||||||
|
return HWBusy;
|
||||||
|
} else if(strstr(result,"posfault") != NULL){
|
||||||
|
return HWPosFault;
|
||||||
|
} else if(strstr(result,"fault") != NULL){
|
||||||
|
return HWFault;
|
||||||
|
} else if(strstr(result,"idle") != NULL){
|
||||||
|
return HWIdle;
|
||||||
|
} else {
|
||||||
|
SCPrintf(pCon,eError,
|
||||||
|
"ERROR: invalid status code %s returned from checkstatus script",
|
||||||
|
result);
|
||||||
|
return HWFault;
|
||||||
}
|
}
|
||||||
return HWFault;
|
return HWFault;
|
||||||
}
|
}
|
||||||
@ -212,6 +211,10 @@ static int SctDriveCommand(SConnection *pCon, SicsInterp *sics, void *object,
|
|||||||
|
|
||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
|
|
||||||
|
if (self->node == NULL) {
|
||||||
|
SCWrite(pCon, "ERROR: defunct object", eError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* only action: print value
|
* only action: print value
|
||||||
*/
|
*/
|
||||||
@ -234,15 +237,26 @@ static void SctDriveKill(void *data){
|
|||||||
}
|
}
|
||||||
free(self);
|
free(self);
|
||||||
}
|
}
|
||||||
|
/*----------------------------------------------------------------*/
|
||||||
|
static hdbCallbackReturn SctDummyCallback(Hdb *node, void *userData,
|
||||||
|
hdbMessage *msg) {
|
||||||
|
return hdbContinue;
|
||||||
|
}
|
||||||
|
/*----------------------------------------------------------------*/
|
||||||
|
static void SctDriveDeleteNode(void *data) {
|
||||||
|
pSctDrive self = (pSctDrive)data;
|
||||||
|
self->node = NULL;
|
||||||
|
}
|
||||||
/*---------------------------------------------------------------*/
|
/*---------------------------------------------------------------*/
|
||||||
int SctMakeDriveAdapter(SConnection *pCon, SicsInterp *pSics, void *object,
|
int SctMakeDriveAdapter(SConnection *pCon, SicsInterp *pSics, void *object,
|
||||||
int argc, char *argv[]) {
|
int argc, char *argv[]) {
|
||||||
pSctDrive pNew = NULL;
|
pSctDrive pNew = NULL;
|
||||||
pSICSOBJ obj = NULL;
|
pSICSOBJ obj = NULL;
|
||||||
|
hdbCallback *cb;
|
||||||
|
|
||||||
pNew = SCTDRIVMakeObject();
|
pNew = SCTDRIVMakeObject();
|
||||||
if(pNew == NULL){
|
if(pNew == NULL){
|
||||||
SCWrite(pCon,"ERROR: out of memory in SctmakeDriveAdapter",
|
SCWrite(pCon,"ERROR: out of memory in SctMakeDriveAdapter",
|
||||||
eError);
|
eError);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -260,7 +274,22 @@ int SctMakeDriveAdapter(SConnection *pCon, SicsInterp *pSics, void *object,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pNew->c =(SctController *)obj->pPrivate;
|
pNew->c =(SctController *)obj->pPrivate;
|
||||||
|
|
||||||
|
if (strcasecmp(argv[0],"dynsctdrive") == 0) {
|
||||||
|
/* make object dynamic by defining a descriptor command */
|
||||||
|
SetDescriptorKey(pNew->pDes, "creationCommand", "0");
|
||||||
|
}
|
||||||
AddCommand(pSics, argv[1], SctDriveCommand, SctDriveKill, pNew);
|
AddCommand(pSics, argv[1], SctDriveCommand, SctDriveKill, pNew);
|
||||||
SetHdbProperty(pNew->node,"sicsdev",argv[1]);
|
SetHdbProperty(pNew->node,"sicsdev",argv[1]);
|
||||||
|
|
||||||
|
cb = MakeHipadabaCallback(SctDummyCallback, pNew, SctDriveDeleteNode);
|
||||||
|
assert(cb);
|
||||||
|
AppendHipadabaCallback(pNew->node, cb);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
/*---------------------------------------------------------------*/
|
||||||
|
void SctDriveInit(void) {
|
||||||
|
AddCmd("makesctdrive", SctMakeDriveAdapter);
|
||||||
|
AddCmd("dynsctdrive", SctMakeDriveAdapter);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user