- allow scriptcontext objects to be dynamic

- enhancements in scriptcontext (error messages stored as properties)
This commit is contained in:
zolliker
2009-02-19 13:30:32 +00:00
parent 981534624f
commit 35f2b6b810
33 changed files with 753 additions and 310 deletions

View File

@ -213,7 +213,9 @@ int RemoveCommand(SicsInterp * pInterp, char *pName)
/* found, remove it */ /* found, remove it */
/* kall KillFunction first */ /* kall KillFunction first */
if (pVictim->KFunc) { if (pVictim->KFunc) {
pVictim->KFunc(pVictim->pData); void *data = pVictim->pData;
pVictim->pData = NULL; /* make data unreachable by FindCommandData before killing */
pVictim->KFunc(data);
} }
/* delete and unlink data */ /* delete and unlink data */
@ -237,7 +239,6 @@ int RemoveCommand(SicsInterp * pInterp, char *pName)
return 1; return 1;
} }
#define MAXLEN 256 #define MAXLEN 256
#define MAXCOM 50 #define MAXCOM 50
extern char *stptok(char *s, char *tok, unsigned int toklen, char *brk); extern char *stptok(char *s, char *tok, unsigned int toklen, char *brk);
@ -1047,10 +1048,9 @@ char *FindAliases(SicsInterp * pSics, char *name)
} }
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
void void ForEachCommand(int (*scanFunction)
ForEachCommand(int (*scanFunction) (char *name, pDummy object, void *userData)
(char *name, pDummy object, void *userData) , void *userData)
, void *userData)
{ {
CommandList *pCurrent; CommandList *pCurrent;

172
ascon.c
View File

@ -14,6 +14,8 @@
#include "ascon.i" #include "ascon.i"
#include "uselect.h" #include "uselect.h"
static double lastClose = 0; /* time of last close operation */
/* /*
CreateSocketAdress stolen from Tcl. Thanks to John Ousterhout CreateSocketAdress stolen from Tcl. Thanks to John Ousterhout
*/ */
@ -60,13 +62,13 @@ double DoubleTime(void)
return now.tv_sec + now.tv_usec / 1e6; return now.tv_sec + now.tv_usec / 1e6;
} }
void AsconError(Ascon * a, char *msg, int errorno) void AsconError(Ascon *a, char *msg, int errorno)
{ {
static char *stateText[] = { static char *stateText[]={
"state 0", "kill", "state 2", "notConnected", "state 0", "state 1", "state 2", "notConnected",
"connect", "start connect", "connect finished", "connect failed", "connect", "start connect", "connect finished", "connect failed",
"write", "start write", "write finished", "write failed", "write", "start write", "write finished", "write failed",
"read", "start read", "read finished", "read failed", "read", "start read", "read finished", "read failed",
"state 16", "state 17", "state 18", "idle" "state 16", "state 17", "state 18", "idle"
}; };
char *state; char *state;
@ -76,13 +78,19 @@ void AsconError(Ascon * a, char *msg, int errorno)
} else { } else {
state = stateText[a->state]; state = stateText[a->state];
} }
if (errorno != 0) { DynStringCopy(a->errmsg, "ASCERR: ");
a->errList = if (errorno == 0) {
ErrPutMsg(a->errList, "ASCERR: %s %s (during %s)", msg, DynStringConcat(a->errmsg, msg);
strerror(errorno), state); DynStringConcat(a->errmsg, " (");
DynStringConcat(a->errmsg, state);
DynStringConcat(a->errmsg, " state)");
} else { } else {
a->errList = DynStringConcat(a->errmsg, strerror(errorno));
ErrPutMsg(a->errList, "ASCERR: %s (during %s)", msg, state); DynStringConcat(a->errmsg, " (");
DynStringConcat(a->errmsg, state);
DynStringConcat(a->errmsg, " state, ");
DynStringConcat(a->errmsg, msg);
DynStringConcat(a->errmsg, ")");
} }
a->state |= AsconFailed; a->state |= AsconFailed;
} }
@ -96,11 +104,23 @@ static void AsconConnect(Ascon * a)
char *colon; char *colon;
int port; int port;
int oldopts; int oldopts;
/* wait 0.5 sec before connecting again after a close
2 reasons for that:
- it seems that connecting immediately to a closed port fails.
We will avoid some "Connection refused" error messages.
- a bug in the lantronix terminal: if a channel is closed and reopened
within short time the connect may be succesful, but a message will be
sent on the channel!
In principle we need only to wait when connecting to the same address
and port, but bookkeeping would be too complicated.
*/
if (DoubleTime() < lastClose + 0.5) return;
if (a->fd < 0) { if (a->fd < 0) {
a->fd = socket(AF_INET, SOCK_STREAM, 0); a->fd = socket(AF_INET, SOCK_STREAM, 0);
if (a->fd < 0) { if (a->fd < 0) {
AsconError(a, "socket failed:", errno); AsconError(a, "ASC1", errno);
return; return;
} }
} }
@ -119,20 +139,19 @@ static void AsconConnect(Ascon * a)
AsconError(a, "bad host specification", 0); AsconError(a, "bad host specification", 0);
return; return;
} }
/* should we insert the workaround for lantronix server ? see network.c */
oldopts = fcntl(a->fd, F_GETFL, 0); oldopts = fcntl(a->fd, F_GETFL, 0);
fcntl(a->fd, F_SETFL, oldopts | O_NONBLOCK); fcntl(a->fd, F_SETFL, oldopts | O_NONBLOCK);
ret = ret =
connect(a->fd, (struct sockaddr *) &adr, sizeof(struct sockaddr_in)); connect(a->fd, (struct sockaddr *) &adr, sizeof(struct sockaddr_in));
if (ret < 0) { if (ret < 0) {
switch (errno) { switch(errno) {
case EINPROGRESS: case EINPROGRESS:
case EALREADY: case EALREADY:
case EISCONN: case EISCONN:
a->state = AsconConnecting; a->state = AsconConnecting;
break; break;
default: default:
AsconError(a, "connect failed:", errno); AsconError(a, "ASC2", errno);
return; return;
} }
} }
@ -140,11 +159,10 @@ static void AsconConnect(Ascon * a)
return; return;
} }
int AsconStdInit(Ascon * a, SConnection * con, int argc, char *argv[]) int AsconStdInit(Ascon *a, SConnection *con, int argc, char *argv[])
{ {
a->fd = -1; a->fd = -1;
a->state = AsconConnectStart; a->state = AsconConnectStart;
a->reconnectInterval = 10;
a->hostport = strdup(argv[1]); a->hostport = strdup(argv[1]);
if (argc > 2) { if (argc > 2) {
a->sendTerminator = strdup(argv[2]); a->sendTerminator = strdup(argv[2]);
@ -154,7 +172,11 @@ int AsconStdInit(Ascon * a, SConnection * con, int argc, char *argv[])
if (argc > 3) { if (argc > 3) {
a->timeout = atof(argv[3]); a->timeout = atof(argv[3]);
} else { } else {
a->timeout = 2.0; /* sec */ a->timeout = 2.0; /* sec */
}
a->replyTerminator == NULL;
if (argc > 4 && argv[4][0] != '\0') {
a->replyTerminator = strdup(argv[4]);
} }
return 1; return 1;
} }
@ -172,9 +194,11 @@ int AsconReadGarbage(int fd)
FD_SET(fd, &rmask); FD_SET(fd, &rmask);
ret = uselect(fd + 1, &rmask, NULL, NULL, &tmo); ret = uselect(fd + 1, &rmask, NULL, NULL, &tmo);
if (ret > 0) { if (ret > 0) {
l = recv(fd, garbage, sizeof garbage, 0); l = recv(fd, garbage, sizeof garbage - 1, 0);
if (l > 0) { if (l > 0) {
/* swallow */ /* swallow */
garbage[l] = '\0';
printf("(((%s)))\n", garbage);
result += l; result += l;
} else if (l == 0) { } else if (l == 0) {
errno = ECONNRESET; errno = ECONNRESET;
@ -307,7 +331,7 @@ int AsconStdHandler(Ascon * a)
} else if (ret > 0) { } else if (ret > 0) {
a->state = AsconConnectDone; /* success */ a->state = AsconConnectDone; /* success */
} else if (ret < 0) { } else if (ret < 0) {
AsconError(a, "AsconConnectSuccess failed:", errno); AsconError(a, "ASC3", errno);
} }
break; break;
case AsconWriteStart: case AsconWriteStart:
@ -320,13 +344,22 @@ int AsconStdHandler(Ascon * a)
} }
break; break;
case AsconWriting: case AsconWriting:
if (a->readState) { /* last char was CR */
ret = AsconReadChar(a->fd, &chr);
if (ret > 0) {
if (chr == '\n') {
/* swallow LF after CR */
a->readState = 0;
} else {
/* garbage character found */
}
}
}
AsconReadGarbage(a->fd); AsconReadGarbage(a->fd);
l = GetDynStringLength(a->wrBuffer) - a->wrPos; l = GetDynStringLength(a->wrBuffer) - a->wrPos;
ret = AsconWriteChars(a->fd, GetCharArray(a->wrBuffer) + a->wrPos, l); ret = AsconWriteChars(a->fd, GetCharArray(a->wrBuffer) + a->wrPos, l);
if (ret < 0) { if (ret < 0) {
if (errno != EINTR && errno != EAGAIN) { AsconError(a, "ASC4", errno);
AsconError(a, "send failed:", errno);
}
/* /*
* Ooops: which state shall we go to after a write fail? * Ooops: which state shall we go to after a write fail?
* This seems to retry. * This seems to retry.
@ -347,23 +380,33 @@ int AsconStdHandler(Ascon * a)
ret = AsconReadChar(a->fd, &chr); ret = AsconReadChar(a->fd, &chr);
while (ret > 0) { while (ret > 0) {
a->start = DoubleTime(); a->start = DoubleTime();
if (chr == '\n') { if (a->replyTerminator != NULL) {
if (a->readState) { if (strchr(a->replyTerminator, chr) != NULL) {
/* swallow LF after CR */ DynStringConcatChar(a->rdBuffer, chr);
DynStringClear(a->rdBuffer);
a->readState = 0;
} else {
DynStringConcatChar(a->rdBuffer, '\0'); DynStringConcatChar(a->rdBuffer, '\0');
a->state = AsconReadDone; a->state = AsconReadDone;
break; break;
} }
} else if (chr == '\r') {
a->readState = 1;
DynStringConcatChar(a->rdBuffer, '\0');
a->state = AsconReadDone;
break;
} else { } else {
if (chr == '\n') {
if (a->readState) { /* last char was CR */
/* swallow LF after CR */
a->readState = 0;
chr = 0;
} else {
DynStringConcatChar(a->rdBuffer, '\0');
a->state = AsconReadDone;
break;
}
} else if (chr == '\r') {
a->readState = 1; /* set 'last char was CR' */
DynStringConcatChar(a->rdBuffer, '\0');
a->state = AsconReadDone;
break;
}
}
if (chr != 0) {
if (DynStringConcatChar(a->rdBuffer, chr) == 0) { if (DynStringConcatChar(a->rdBuffer, chr) == 0) {
AsconError(a, "DynStringConcatChar failed:", ENOMEM); AsconError(a, "DynStringConcatChar failed:", ENOMEM);
break; break;
@ -375,7 +418,7 @@ int AsconStdHandler(Ascon * a)
if (ret < 0) { if (ret < 0) {
/* EINTR means we shall retry */ /* EINTR means we shall retry */
if (errno != EINTR && errno != EAGAIN) { if (errno != EINTR && errno != EAGAIN) {
AsconError(a, "AsconReadChar failed:", errno); AsconError(a, "ASC5", errno);
} }
return 1; return 1;
} }
@ -384,30 +427,26 @@ int AsconStdHandler(Ascon * a)
} else { } else {
if (a->timeout > 0) { if (a->timeout > 0) {
if (DoubleTime() - a->start > a->timeout) { if (DoubleTime() - a->start > a->timeout) {
AsconError(a, "read timeout", 0); AsconError(a, "no response", 0);
a->state = AsconTimeout; a->state = AsconTimeout;
} }
} }
} }
break; break;
default: default:
return 1; break;
} }
return 1; return 1;
} }
/* define type AsconProtocolList and functions AsconProtocolAdd etc. */ static AsconProtocol *protocols = NULL;
#define MC_NAME(T) AsconProtocol##T
#include "mclist.c"
static AsconProtocolList protocols = { 0 }; void AsconInsertProtocol(AsconProtocol *protocol) {
protocol->next = protocols;
void AsconInsertProtocol(AsconProtocol * protocol) protocols = protocol;
{
AsconProtocolAdd(&protocols, protocol);
} }
AsconHandler AsconSetHandler(Ascon * a, SConnection * con, AsconHandler AsconSetHandler(Ascon *a, SConnection *con,
int argc, char *argv[]) int argc, char *argv[])
{ {
AsconProtocol *p; AsconProtocol *p;
@ -420,7 +459,7 @@ AsconHandler AsconSetHandler(Ascon * a, SConnection * con,
AsconStdInit(a, con, argc, argv); AsconStdInit(a, con, argc, argv);
return AsconStdHandler; return AsconStdHandler;
} }
for (p = protocols.head; p != NULL; p = p->next) { for (p = protocols; p!= NULL; p=p->next) {
if (strcasecmp(p->name, argv[0]) == 0) { if (strcasecmp(p->name, argv[0]) == 0) {
if (p->init(a, con, argc, argv)) { if (p->init(a, con, argc, argv)) {
return p->handler; return p->handler;
@ -460,10 +499,8 @@ Ascon *AsconMake(SConnection * con, int argc, char *argv[])
} }
a->rdBuffer = CreateDynString(60, 63); a->rdBuffer = CreateDynString(60, 63);
a->wrBuffer = CreateDynString(60, 63); a->wrBuffer = CreateDynString(60, 63);
a->errList = NULL; a->errmsg = CreateDynString(60, 63);
a->responseValid = 0; a->responseValid = 0;
a->reconnectInterval = 10;
a->lastReconnect = 0;
return a; return a;
} }
@ -471,15 +508,20 @@ void AsconKill(Ascon * a)
{ {
if (a->fd > 0) { if (a->fd > 0) {
close(a->fd); close(a->fd);
lastClose = DoubleTime();
} }
DeleteDynString(a->rdBuffer); DeleteDynString(a->rdBuffer);
DeleteDynString(a->wrBuffer); DeleteDynString(a->wrBuffer);
DeleteDynString(a->errmsg);
if (a->hostport) { if (a->hostport) {
free(a->hostport); free(a->hostport);
} }
if (a->sendTerminator) { if(a->sendTerminator){
free(a->sendTerminator); free(a->sendTerminator);
} }
if(a->replyTerminator){
free(a->replyTerminator);
}
if (a->private != NULL && a->killPrivate != NULL) { if (a->private != NULL && a->killPrivate != NULL) {
a->killPrivate(a->private); a->killPrivate(a->private);
} }
@ -528,17 +570,15 @@ AsconStatus AsconTask(Ascon * a)
case AsconStart: case AsconStart:
return AsconPending; return AsconPending;
case AsconFailed: case AsconFailed:
if (a->state != AsconTimeout) { if (a->state == AsconTimeout) {
now = DoubleTime(); a->state = AsconIdle;
if (now > a->lastReconnect + a->reconnectInterval) { } else {
a->lastReconnect = now; close(a->fd);
close(a->fd); lastClose = DoubleTime();
/* allow the system to cleanup the socket, otherwise a reconnect will fail */ a->fd = -1;
sleep(1); a->state = AsconConnectStart;
a->fd = -1;
a->state = AsconConnectStart;
}
} }
return AsconFailure; return AsconFailure;
case AsconFinished: case AsconFinished:
if (a->state < AsconConnectFailed) { if (a->state < AsconConnectFailed) {
@ -580,7 +620,7 @@ char *AsconRead(Ascon * a)
return NULL; return NULL;
} }
ErrMsg *AsconGetErrList(Ascon * a) char *AsconGetError(Ascon *a)
{ {
return a->errList; return GetCharArray(a->errmsg);
} }

15
ascon.h
View File

@ -2,7 +2,6 @@
#define ASCON_H #define ASCON_H
#include "sics.h" #include "sics.h"
#include "errormsg.h"
/** \file /** \file
* \brief Asynchronous connection handling for devices controlled over tcp-ip * \brief Asynchronous connection handling for devices controlled over tcp-ip
@ -60,15 +59,17 @@ int AsconWrite(Ascon * a, char *command, int noResponse);
* \return the response when a response is ready * \return the response when a response is ready
* NULL when the command has not completed and the response is not yet finished * NULL when the command has not completed and the response is not yet finished
* "" when the command has completed, but no response was expected. * "" when the command has completed, but no response was expected.
* The result is only valid until the next call to other AsconXxx functions * The result is only valid until the next call to any AsconXxx function
* and has to be duplicated if needed later. * with the same connection and has to be duplicated if needed later.
*/ */
char *AsconRead(Ascon * a); char *AsconRead(Ascon * a);
/** \brief get the connections error list /** \brief get the last error message
* \return the error list * \return the error message
* The result is only valid until the next call to any AsconXxx function
* with the same connection and has to be duplicated if needed later.
*/ */
ErrMsg *AsconGetErrList(Ascon * a); char *AsconGetError(Ascon *a);
/** \brief a helper function /** \brief a helper function
* \param argc the number of args * \param argc the number of args
@ -78,7 +79,7 @@ ErrMsg *AsconGetErrList(Ascon * a);
*/ */
char *ConcatArgs(int argc, char *argv[]); char *ConcatArgs(int argc, char *argv[]);
/** \brief function for dealing with times with musec resolution /** \brief function for dealing with times with microsec resolution
* \return absolute time as double value * \return absolute time as double value
*/ */
double DoubleTime(void); double DoubleTime(void);

14
ascon.i
View File

@ -12,7 +12,7 @@
* For the implementation of a custom protocol, you have to implement * For the implementation of a custom protocol, you have to implement
* the handler function and the init function, declare the protocol * the handler function and the init function, declare the protocol
* of type AsconProtocol and call AsconInsertProtocol on startup. * of type AsconProtocol and call AsconInsertProtocol on startup.
* The handler and init functions are normally be a wrapper around AsconStdHandler * The handler and init functions are normally a wrapper around AsconStdHandler
* and AsconStdInit * and AsconStdInit
* *
* The functions with fd as the first argument are utility functions with * The functions with fd as the first argument are utility functions with
@ -64,8 +64,9 @@ struct Ascon {
int wrPos; /**< write buffer position */ int wrPos; /**< write buffer position */
double timeout; /**< read timeout (sec) */ double timeout; /**< read timeout (sec) */
char *sendTerminator; /**< terminator for sending messages */ char *sendTerminator; /**< terminator for sending messages */
char *replyTerminator; /**< terminator list for reply. NULL is the special case CR, LF or CR/LF */
char *hostport; /**< host:port to connect */ char *hostport; /**< host:port to connect */
ErrMsg *errList; /**< error message list */ pDynString errmsg; /**< error message */
double start; /**< unix time when read was started */ double start; /**< unix time when read was started */
void *private; /**< private data of protocol */ void *private; /**< private data of protocol */
void (*killPrivate)(void *); /** < kill function for private */ void (*killPrivate)(void *); /** < kill function for private */
@ -73,7 +74,6 @@ struct Ascon {
int responseValid; /**< a valid response is ready */ int responseValid; /**< a valid response is ready */
AsconHandler handler; /**< handler function */ AsconHandler handler; /**< handler function */
double reconnectInterval; /**< reconnect interval */ double reconnectInterval; /**< reconnect interval */
double lastReconnect; /**< last connect try */
}; };
#define ASCON_SELECT_ERROR -1 #define ASCON_SELECT_ERROR -1
@ -92,7 +92,13 @@ int AsconStdHandler(Ascon *a);
/** \brief initialize a standard connection /** \brief initialize a standard connection
* \param a the connection * \param a the connection
* \param con A connection to print errors too. * \param con A connection to print errors too.
* \param hostport the tcp/ip address (syntax: host:port) * \param argc number of arguments
* \param argv arguments ("<host>:<port>" [sendTerminator] [timeout] [replyTerminators])
* sendTerminator is a character or string sent at the end of a command
* timoeut is in seconds
* replyTerminator is a string, meant as a list of terminator characters
* if not replyTerminator is given, CR, LF or CR/LF all are detected as
* terminators
* *
* In most cases a custom init function may be a wrapper around AsconStdInit * In most cases a custom init function may be a wrapper around AsconStdInit
*/ */

View File

@ -89,7 +89,6 @@ void WriteToCommandLogId(char *prompt, int id, char *text)
return; return;
strncpy(pCopy, text, l); strncpy(pCopy, text, l);
pCopy[l] = '\0'; pCopy[l] = '\0';
if (prompt == cmdPrompt && iCompact) { if (prompt == cmdPrompt && iCompact) {
pPtr = strstr(pCopy, "fulltransact "); pPtr = strstr(pCopy, "fulltransact ");
if (pPtr && pPtr < pCopy + 3) { if (pPtr && pPtr < pCopy + 3) {
@ -101,17 +100,30 @@ void WriteToCommandLogId(char *prompt, int id, char *text)
} }
} }
now = time(NULL);
/* create tail buffer as needed */ /* create tail buffer as needed */
if (!pTail) { if (!pTail) {
pTail = createCircular(MAXTAIL, free); pTail = createCircular(MAXTAIL, free);
} }
now = time(NULL);
doStamp = 0; doStamp = 0;
doStampId = 0; doStampId = 0;
if (id == NOID) { if (iCompact == 1) {
nowTm = localtime(&now);
strftime(stamp1, sizeof stamp1, "%H:%M:%S", nowTm);
if (prompt == NULL)
prompt = "";
if (id == NOID) {
if (!prompt)
prompt = " ";
snprintf(buffer, sizeof buffer, "%s %s ", stamp1, prompt);
} else {
snprintf(buffer, sizeof buffer, "%s %2.0d| ", stamp1, id);
}
prompt = buffer;
} else if (id == NOID) {
if (!prompt) { if (!prompt) {
prompt = ""; prompt = "";
} else { } else {
@ -125,7 +137,7 @@ void WriteToCommandLogId(char *prompt, int id, char *text)
snprintf(buffer, sizeof buffer, "sock %d>%s ", id, prompt); snprintf(buffer, sizeof buffer, "sock %d>%s ", id, prompt);
} }
prompt = buffer; prompt = buffer;
} else { } else if (iCompact > 1) {
if (id != lastId) { if (id != lastId) {
lastId = id; lastId = id;
doStampId = 1; doStampId = 1;
@ -138,7 +150,7 @@ void WriteToCommandLogId(char *prompt, int id, char *text)
} }
} }
if (iCompact > 0) { /* write time stamp */ if (iCompact > 1) { /* write time stamp */
if (now / iCompact != lastStamp / iCompact) { if (now / iCompact != lastStamp / iCompact) {
doStamp = 1; doStamp = 1;
doStampId = 1; doStampId = 1;

View File

@ -788,6 +788,40 @@ int StopExe(pExeList self, char *name)
return 0; return 0;
} }
/*-------------------------------------------------------------------------*/
int StopByData(pExeList self, void *data)
{
int iRet;
pDevEntry pDev = NULL;
pIDrivable pDrivInt = NULL;
pICountable pCountInt = NULL;
iRet = LLDnodePtr2First(self->iList);
while (iRet != 0) {
pDev = (pDevEntry) LLDnodePtr(self->iList);
if (pDev) {
if (pDev->pData == data) {
pDrivInt = pDev->pDescriptor->GetInterface(pDev->pData, DRIVEID);
pCountInt = pDev->pDescriptor->GetInterface(pDev->pData, COUNTID);
if (pDrivInt) {
pDrivInt->Halt(pDev->pData);
} else if (pCountInt) {
pCountInt->Halt(pDev->pData);
}
ExeInterest(self, pDev, "finished");
DevexecLog("FINISHED", pDev->name);
DeleteDevEntry(pDev);
LLDnodeDelete(self->iList);
self->iStatus = DEVDONE;
SCWrite(self->pOwner, "", eFinish);
return 1;
}
}
iRet = LLDnodePtr2Next(self->iList);
}
return 0;
}
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
int StopExeWait(pExeList self) int StopExeWait(pExeList self)
{ {
@ -795,7 +829,6 @@ int StopExeWait(pExeList self)
Wait4Success(self); Wait4Success(self);
return 1; return 1;
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
int PauseExecution(pExeList self) int PauseExecution(pExeList self)
{ {
@ -1006,7 +1039,6 @@ int SicsIdle(SConnection * pCon, SicsInterp * pSics, void *pData,
Usage: Usage:
Success Success
*/ */
int Success(SConnection * pCon, SicsInterp * pSics, void *pData, int Success(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[]) int argc, char *argv[])
{ {
@ -1020,6 +1052,8 @@ int Success(SConnection * pCon, SicsInterp * pSics, void *pData,
if (SCGetInterrupt(pCon) == eAbortOperation) { if (SCGetInterrupt(pCon) == eAbortOperation) {
SCSetInterrupt(pCon, eContinue); SCSetInterrupt(pCon, eContinue);
iRet = 0; iRet = 0;
} else {
iRet = 1;
} }
} else if (iRet == DEVDONE) { } else if (iRet == DEVDONE) {
SCWrite(pCon, "All done", eValue); SCWrite(pCon, "All done", eValue);
@ -1031,7 +1065,6 @@ int Success(SConnection * pCon, SicsInterp * pSics, void *pData,
SetStatus(eEager); SetStatus(eEager);
return iRet; return iRet;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
int PauseAction(SConnection * pCon, SicsInterp * pSics, void *pData, int PauseAction(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[]) int argc, char *argv[])

View File

@ -1,5 +1,5 @@
#line 195 "devexec.w" #line 197 "devexec.w"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@ -54,7 +54,7 @@ int StartMotor(pExeList self, SicsInterp * pSics, SConnection * pCon,
int StartCounter(pExeList self, SicsInterp * pSics, SConnection * pCon, int StartCounter(pExeList self, SicsInterp * pSics, SConnection * pCon,
char *name); char *name);
#line 239 "devexec.w" #line 241 "devexec.w"
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
@ -73,7 +73,7 @@ int DevExecTask(void *pEL);
void DevExecSignal(void *pEL, int iSignal, void *pSigData); void DevExecSignal(void *pEL, int iSignal, void *pSigData);
#line 241 "devexec.w" #line 243 "devexec.w"
/* /*
@ -104,6 +104,9 @@ int StopExeWait(pExeList self);
StopExeWait will stop all running things and wait for the stop StopExeWait will stop all running things and wait for the stop
to complete. to complete.
*/ */
int StopByData(pExeList self, void *data);
/* stop the entry with the given data from execution */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
void ClearExecutor(pExeList self); void ClearExecutor(pExeList self);
/* /*
@ -115,7 +118,7 @@ int PauseExecution(pExeList self);
int ContinueExecution(pExeList self); int ContinueExecution(pExeList self);
#line 259 "devexec.w" #line 261 "devexec.w"
/*-------------------------- Commands ------------------------------------*/ /*-------------------------- Commands ------------------------------------*/
int DevexecAction(SConnection * pCon, SicsInterp * pSics, void *pData, int DevexecAction(SConnection * pCon, SicsInterp * pSics, void *pData,
@ -157,16 +160,15 @@ int ContinueAction(SConnection * pCon, SicsInterp * pSics, void *pData,
/*--------------------------- Locking ---------------------------------*/ /*--------------------------- Locking ---------------------------------*/
#line 183 "devexec.w" #line 185 "devexec.w"
void LockDeviceExecutor(pExeList self); void LockDeviceExecutor(pExeList self);
void UnlockDeviceExecutor(pExeList self); void UnlockDeviceExecutor(pExeList self);
#line 299 "devexec.w" #line 301 "devexec.w"
/* -------------------------- Executor management -------------------------*/ /* -------------------------- Executor management -------------------------*/
pExeList GetExecutor(void); pExeList GetExecutor(void);
void SetExecutor(pExeList pExe); void SetExecutor(pExeList pExe);
/*----------------------- Logging -----------------------------------------*/ /*----------------------- Logging -----------------------------------------*/

View File

@ -52,7 +52,7 @@ $\langle$devreg {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ char *name, float fNew);@\\ \mbox{}\verb@ char *name, float fNew);@\\
\mbox{}\verb@ int StartCounter(pExeList self, SicsInterp *pSics, SConnection *pCon,@\\ \mbox{}\verb@ int StartCounter(pExeList self, SicsInterp *pSics, SConnection *pCon,@\\
\mbox{}\verb@ char *name); @\\ \mbox{}\verb@ char *name); @\\
\mbox{}\verb@@$\diamond$ \mbox{}\verb@@$\Diamond$
\end{list} \end{list}
\vspace{-1ex} \vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex}
@ -115,7 +115,7 @@ $\langle$devcheck {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int DevExecTask(void *pEL);@\\ \mbox{}\verb@ int DevExecTask(void *pEL);@\\
\mbox{}\verb@ void DevExecSignal(void *pEL, int iSignal, void *pSigData);@\\ \mbox{}\verb@ void DevExecSignal(void *pEL, int iSignal, void *pSigData);@\\
\mbox{}\verb@@\\ \mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$ \mbox{}\verb@@$\Diamond$
\end{list} \end{list}
\vspace{-1ex} \vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex}
@ -174,6 +174,8 @@ $\langle$devstop {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ StopExeWait will stop all running things and wait for the stop@\\ \mbox{}\verb@ StopExeWait will stop all running things and wait for the stop@\\
\mbox{}\verb@ to complete.@\\ \mbox{}\verb@ to complete.@\\
\mbox{}\verb@ */@\\ \mbox{}\verb@ */@\\
\mbox{}\verb@ int StopByData(pExeList self, void *data);@\\
\mbox{}\verb@ /* stop the entry with the given data from execution */@\\
\mbox{}\verb@/*------------------------------------------------------------------------*/@\\ \mbox{}\verb@/*------------------------------------------------------------------------*/@\\
\mbox{}\verb@ void ClearExecutor(pExeList self);@\\ \mbox{}\verb@ void ClearExecutor(pExeList self);@\\
\mbox{}\verb@ /*@\\ \mbox{}\verb@ /*@\\
@ -184,7 +186,7 @@ $\langle$devstop {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int PauseExecution(pExeList self);@\\ \mbox{}\verb@ int PauseExecution(pExeList self);@\\
\mbox{}\verb@ int ContinueExecution(pExeList self);@\\ \mbox{}\verb@ int ContinueExecution(pExeList self);@\\
\mbox{}\verb@@\\ \mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$ \mbox{}\verb@@$\Diamond$
\end{list} \end{list}
\vspace{-1ex} \vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex}
@ -226,7 +228,7 @@ $\langle$devlock {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ void LockDeviceExecutor(pExeList self);@\\ \mbox{}\verb@ void LockDeviceExecutor(pExeList self);@\\
\mbox{}\verb@ void UnlockDeviceExecutor(pExeList self);@\\ \mbox{}\verb@ void UnlockDeviceExecutor(pExeList self);@\\
\mbox{}\verb@@\\ \mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$ \mbox{}\verb@@$\Diamond$
\end{list} \end{list}
\vspace{-1ex} \vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex} \footnotesize\addtolength{\baselineskip}{-1ex}
@ -358,7 +360,7 @@ to the global SICS device executor.
\mbox{}\verb@/*----------------------- Logging -----------------------------------------*/@\\ \mbox{}\verb@/*----------------------- Logging -----------------------------------------*/@\\
\mbox{}\verb@ void DevexecLog(char *op, char *device); @\\ \mbox{}\verb@ void DevexecLog(char *op, char *device); @\\
\mbox{}\verb@#endif @\\ \mbox{}\verb@#endif @\\
\mbox{}\verb@@$\diamond$ \mbox{}\verb@@$\Diamond$
\end{list} \end{list}
\vspace{-2ex} \vspace{-2ex}
\end{minipage}\\[4ex] \end{minipage}\\[4ex]

View File

@ -144,6 +144,8 @@ This is done via the following interface.
StopExeWait will stop all running things and wait for the stop StopExeWait will stop all running things and wait for the stop
to complete. to complete.
*/ */
int StopByData(pExeList self, void *data);
/* stop the entry with the given data from execution */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
void ClearExecutor(pExeList self); void ClearExecutor(pExeList self);
/* /*

View File

@ -24,14 +24,14 @@ struct DevSer {
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 */
SchedHeader *headers; SchedHeader *headers;
ErrMsg *errmsg;
int steps; int steps;
int stopTask; int stopTask;
}; };
static char *devPrio[NumberOfPRIO] = { static char *devPrio[NumberOfPRIO] = {
"null", "slow", "read", "progress", "write", "halt" "null", "slow", "read", "progress", "write", "halt", "start"
}; };
char *DevPrio2Text(DevPrio prio) char *DevPrio2Text(DevPrio prio)
@ -100,6 +100,9 @@ DevAction *DevNextAction(DevSer * devser)
header->timeDue = (floor(now / header->interval) + 1) header->timeDue = (floor(now / header->interval) + 1)
* header->interval; * header->interval;
} }
} else if (header->prio == StartPRIO && header->actions != NULL) {
/* special case: poll with StartPRIO pending: block all other actions */
return devser->current;
} }
} }
if (header->followingAction != NULL) { if (header->followingAction != NULL) {
@ -123,13 +126,18 @@ int DevQueueTask(void *ds)
AsconStatus status; AsconStatus status;
DevAction *action; DevAction *action;
char *sendData; char *sendData;
char *replyData; char *replyData = NULL;
if (devser->steps == 0) if (devser->steps == 0)
return 1; return 1;
if (devser->stopTask) { if (devser->stopTask) {
return 0; return 0;
} }
/* deferred deallocation of removed actions */
DevFreeActionList(devser->toKill);
devser->toKill = NULL;
action = devser->current; action = devser->current;
if (action == NULL) { if (action == NULL) {
action = DevNextAction(devser); action = DevNextAction(devser);
@ -138,19 +146,16 @@ int DevQueueTask(void *ds)
while (action != NULL) { while (action != NULL) {
status = AsconTask(devser->asyncConn); status = AsconTask(devser->asyncConn);
if (status == AsconFailure) { if (status == AsconFailure) {
devser->errmsg = AsconGetErrList(devser->asyncConn); replyData = AsconGetError(devser->asyncConn);
} else if (status != AsconReady) { } else if (status == AsconReady) {
replyData = AsconRead(devser->asyncConn);
} else {
return 1; return 1;
} }
if (devser->steps > 0) { /* debugging mode */ if (devser->steps > 0) { /* debugging mode */
devser->steps--; devser->steps--;
} }
if (status == AsconFailure) { sendData = action->hdl(action->data, replyData, (status == AsconFailure));
replyData = devser->errmsg->text;
} else {
replyData = AsconRead(devser->asyncConn);
}
sendData = action->hdl(action->data, replyData);
if (sendData != NULL) { if (sendData != NULL) {
AsconWrite(devser->asyncConn, sendData, 0); AsconWrite(devser->asyncConn, sendData, 0);
return 1; return 1;
@ -184,6 +189,7 @@ DevSer *DevMake(SConnection * con, int argc, char *argv[])
devser->actions = NULL; devser->actions = NULL;
devser->headers = NULL; devser->headers = NULL;
devser->stopTask = 0; devser->stopTask = 0;
devser->toKill = NULL;
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;
@ -216,6 +222,7 @@ void DevKill(DevSer * devser)
AsconKill(devser->asyncConn); AsconKill(devser->asyncConn);
} }
DevFreeActionList(devser->actions); DevFreeActionList(devser->actions);
DevFreeActionList(devser->toKill);
h = devser->headers; h = devser->headers;
while (h != NULL) { while (h != NULL) {
victim = h; victim = h;
@ -223,6 +230,11 @@ void DevKill(DevSer * devser)
DevFreeActionList(victim->actions); DevFreeActionList(victim->actions);
free(victim); free(victim);
} }
if (devser->killCurrent) {
if (devser->current->kill != NULL) devser->current->kill(devser->current);
devser->killCurrent = 0;
free(devser->current);
}
if (devser->stopTask) { if (devser->stopTask) {
free(devser); free(devser);
} else { } else {
@ -286,9 +298,9 @@ int DevUnschedule(DevSer * devser, void *actionData,
cnt++; cnt++;
/* remove from list */ /* remove from list */
*ptr2Last = action->next; *ptr2Last = action->next;
if (action->kill != NULL) /* add to kill list */
action->kill(action->data); action->next = devser->toKill;
free(action); devser->toKill = action;
} else { } else {
ptr2Last = &action->next; ptr2Last = &action->next;
} }
@ -360,12 +372,13 @@ int DevRemoveAction(DevSer * devser, void *actionData)
{ {
SchedHeader *header = NULL; SchedHeader *header = NULL;
DevAction **ptr2Last = NULL; DevAction **ptr2Last = NULL;
DevAction *action = NULL; DevAction *action = NULL;
int cnt = 0; int cnt = 0;
/* Remove current action, if matched. If a reply is pending, the next action will /* Remove current action, if matched. If a reply is pending, the next
get the reply. But as in the inital state no reply is expected, this should not harm. */ action will get the reply. But as in the inital state no reply is
expected, this should not harm. */
action = devser->current; action = devser->current;
if (action != NULL && actionData == action->data) { if (action != NULL && actionData == action->data) {
if (devser->killCurrent) { if (devser->killCurrent) {
@ -378,7 +391,7 @@ int DevRemoveAction(DevSer * devser, void *actionData)
} }
/* remove from queue */ /* remove from queue */
ptr2Last = &devser->actions; ptr2Last = &devser->actions;
for (action = devser->actions; action != NULL; action = action->next) { for (action = devser->actions; action != NULL; action = *ptr2Last) {
if (actionData == action->data) { if (actionData == action->data) {
cnt++; cnt++;
/* remove from list */ /* remove from list */

View File

@ -10,10 +10,12 @@ typedef struct DevSer DevSer;
/** \brief The action handler to be called /** \brief The action handler to be called
* \param actionData the data stored with the action * \param actionData the data stored with the action
* \param lastReply the last reply or NULL when no command was * \param lastReply the last reply or NULL when no command was
* sent in the last action * sent in the last action, or the error message (when commError == 1)
* \param commError 0: ok, 1: there was a communication error
* \return the command to be sent or NULL if no command has to be sent * \return the command to be sent or NULL if no command has to be sent
*/ */
typedef char *DevActionHandler(void *actionData, char *lastReply); typedef char *DevActionHandler(void *actionData, char *lastReply,
int commError);
/** \brief Check if an action matches the call data /** \brief Check if an action matches the call data
* \param callData the callers data * \param callData the callers data
@ -29,10 +31,12 @@ typedef void DevKillActionData(void *actionData);
/** \brief possible priorities. /** \brief possible priorities.
* NullPRIO and NumberOfPRIO must not be used as priority * NullPRIO and NumberOfPRIO must not be used as priority
* if an action with StartPRIO is scheduled, all other activities
* are blocked until the action is unscheduled
*/ */
typedef enum { typedef enum {
NullPRIO, SlowPRIO, ReadPRIO, ProgressPRIO, WritePRIO, HaltPRIO, NullPRIO, SlowPRIO, ReadPRIO, ProgressPRIO, WritePRIO, HaltPRIO,
NumberOfPRIO StartPRIO, NumberOfPRIO
} DevPrio; } DevPrio;
/** \brief Make a new device serializer and async connection. /** \brief Make a new device serializer and async connection.
@ -100,7 +104,7 @@ int DevSchedule(DevSer * devser, void *actionData,
/** \brief Unschedule matching actions /** \brief Unschedule matching actions
* \param devser the device serializer * \param devser the device serializer
* \param callData the callers data to be as first argument of the match function * \param actionData 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 the match function (callData does not need to have the same type as actionData)
* \return the number of unscheduled actions * \return the number of unscheduled actions
@ -114,6 +118,7 @@ int DevUnschedule(DevSer * devser, void *actionData,
*/ */
int DevRemoveAction(DevSer * devser, void *actionData); 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
@ -126,5 +131,4 @@ char *DevPrio2Text(DevPrio prio);
*/ */
DevPrio DevText2Prio(char *text); DevPrio DevText2Prio(char *text);
#endif #endif

View File

@ -26,7 +26,7 @@ int ErrEqual(char *str1, char *str2)
return 1; return 1;
} }
ErrMsg *ErrPutMsg(ErrMsg * dump, char *fmt, ...) void ErrPutMsg(ErrList *list, char *fmt, ...)
{ {
ErrMsg *m = NULL; ErrMsg *m = NULL;
ErrMsg **last = NULL; ErrMsg **last = NULL;
@ -34,7 +34,8 @@ ErrMsg *ErrPutMsg(ErrMsg * dump, char *fmt, ...)
char buf[256]; char buf[256];
char *text = NULL; char *text = NULL;
int l; int l;
static long id = 0;
va_start(ap, fmt); va_start(ap, fmt);
l = vsnprintf(buf, sizeof buf, fmt, ap); l = vsnprintf(buf, sizeof buf, fmt, ap);
va_end(ap); va_end(ap);
@ -43,12 +44,13 @@ ErrMsg *ErrPutMsg(ErrMsg * dump, char *fmt, ...)
} else { } else {
/* assuming we have a C99 conforming snprintf and need a larger buffer */ /* assuming we have a C99 conforming snprintf and need a larger buffer */
text = calloc(l, 1); text = calloc(l, 1);
if (!text) return;
va_start(ap, fmt); va_start(ap, fmt);
vsnprintf(text, l, fmt, ap); vsnprintf(text, l, fmt, ap);
va_end(ap); va_end(ap);
} }
last = &dump; last = &list->current;
for (m = dump; m != NULL; m = m->next) { for (m = list->current; m != NULL; m = m->next) {
if (ErrEqual(text, m->text)) { if (ErrEqual(text, m->text)) {
*last = m->next; /* remove found item from list */ *last = m->next; /* remove found item from list */
break; break;
@ -61,12 +63,21 @@ ErrMsg *ErrPutMsg(ErrMsg * dump, char *fmt, ...)
m = calloc(1, sizeof(*m)); m = calloc(1, sizeof(*m));
m->text = text; m->text = text;
m->cnt = 1; m->cnt = 1;
m->dirty = 0;
id++;
m->id = id;
} else { } else {
if (text != buf) if (text != buf)
free(text); free(text);
m->cnt++; m->cnt++;
} }
m->next = dump; m->next = list->current;
time(&m->last); time(&m->last);
return m; list->current = m;
}
char *ErrGetLastMsg(ErrList *list) {
if (list == NULL) return "";
if (list->current == NULL) return "";
return list->current->text;
} }

View File

@ -11,10 +11,17 @@
typedef struct ErrMsg { typedef struct ErrMsg {
struct ErrMsg *next; struct ErrMsg *next;
char *text; /**< the message text */ char *text; /**< the message text */
int cnt; /**< count */ long cnt; /**< count */
time_t last; /**< time of last message */ time_t last; /**< time of last message */
long dirty; /**< count since last reset */
char *itemId; /**< an id for the item where the error occured */
long id;
} ErrMsg; } ErrMsg;
typedef struct {
ErrMsg *current;
} ErrList;
/** \brief Put a formatted message to the error message list /** \brief Put a formatted message to the error message list
* *
* The error message list contains only one entry for all messages * The error message list contains only one entry for all messages
@ -23,10 +30,17 @@ typedef struct ErrMsg {
* when comparing messages. * when comparing messages.
* The new message is always at the head of the list. * The new message is always at the head of the list.
* *
* \param dump the error message list * \param list the error message list
* \param fmt the format for the message * \param fmt the format for the message
* \return the new error message list head * \return the new error message list head
*/ */
ErrMsg *ErrPutMsg(ErrMsg * dump, char *fmt, ...);
void ErrPutMsg(ErrList *list, char *fmt, ...);
/** \brief Get the most recent error message
* \param list the error list
* \return the most recent error message
*/
char *ErrGetLastMsg(ErrList *list);
#endif #endif

View File

@ -86,6 +86,7 @@ void DeleteCallbackChain(pHdb node)
InvokeCallbackChain(node, &killNodeMsg); InvokeCallbackChain(node, &killNodeMsg);
current = node->callBackChain; current = node->callBackChain;
node->callBackChain = NULL;
while (current != NULL) { while (current != NULL) {
if (current->killFunc != NULL) { if (current->killFunc != NULL) {
current->killFunc(current->userData); current->killFunc(current->userData);

25
macro.c
View File

@ -982,14 +982,6 @@ int TclPublish(SConnection * pCon, SicsInterp * pSics, void *pData,
return 0; return 0;
} }
/* check user rights */
if (!SCMatchRights(pCon, usMugger)) {
sprintf(pBueffel, "ERROR: you are not authorised to use %s", argv[0]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* try convert last parameter to user code */ /* try convert last parameter to user code */
iUser = decodeSICSPriv(argv[2]); iUser = decodeSICSPriv(argv[2]);
if (iUser < 0) { if (iUser < 0) {
@ -1002,9 +994,26 @@ int TclPublish(SConnection * pCon, SicsInterp * pSics, void *pData,
/* check if the macro already exists */ /* check if the macro already exists */
pNew = FindCommandData(pSics, argv[1], "Macro"); pNew = FindCommandData(pSics, argv[1], "Macro");
if (pNew) { /* yes -> overwrite access code */ if (pNew) { /* yes -> overwrite access code */
if (pNew->iUser == iUser) {
return 1;
}
/* check user rights */
if (!SCMatchRights(pCon, usMugger)) {
sprintf(pBueffel, "ERROR: you are not authorised to use %s", argv[0]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
pNew->iUser = iUser; pNew->iUser = iUser;
return 1; return 1;
} }
/* check user rights */
if (!SCMatchRights(pCon, usMugger)) {
sprintf(pBueffel, "ERROR: you are not authorised to use %s", argv[0]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
/* do a job ! */ /* do a job ! */
pNew = CreatePublish(argv[1], iUser); pNew = CreatePublish(argv[1], iUser);
if (!pNew) { if (!pNew) {

View File

@ -31,7 +31,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
hmdata.o nxscript.o tclintimpl.o sicsdata.o mcstascounter.o \ hmdata.o nxscript.o tclintimpl.o sicsdata.o mcstascounter.o \
mcstashm.o initializer.o remob.o tclmotdriv.o protocol.o \ mcstashm.o initializer.o remob.o tclmotdriv.o protocol.o \
sinfox.o sicslist.o cone.o hipadaba.o sicshipadaba.o statistics.o \ sinfox.o sicslist.o cone.o hipadaba.o sicshipadaba.o statistics.o \
ascon.o errormsg.o scriptcontext.o logger.o logreader.o logsetup.o \ ascon.o scriptcontext.o logger.o logreader.o logsetup.o \
savehdb.o statusfile.o sicshdbfactory.o proxy.o devser.o \ savehdb.o statusfile.o sicshdbfactory.o proxy.o devser.o \
moregress.o multicounter.o regresscter.o histregress.o \ moregress.o multicounter.o regresscter.o histregress.o \
sicshdbadapter.o polldriv.o sicspoll.o statemon.o hmslave.o \ sicshdbadapter.o polldriv.o sicspoll.o statemon.o hmslave.o \
@ -63,7 +63,7 @@ full: purge all
SICServer: $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) \ SICServer: $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) \
$(VELOOBJ) $(DIFIL) $(EXTRA) \ $(VELOOBJ) $(DIFIL) $(EXTRA) \
$(SUBLIBS) $(SUBLIBS)
$(CC) -g -o SICServer \ $(CC) -g -o SICServer \
$(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) \ $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) \
$(VELOOBJ) $(DIFOBJ) $(EXTRA) $(LIBS) $(VELOOBJ) $(DIFOBJ) $(EXTRA) $(LIBS)

29
motor.c
View File

@ -128,28 +128,25 @@ static int MotorCheckBoundaryImpl(pMotor self, float fVal, float *fNew,
{ {
float fHard; float fHard;
float fZero; float fZero;
char pBueffel[512]; float fLim;
assert(self); assert(self);
/* check for fixed */ /* check for fixed */
if (ObVal(self->ParArray, FIX) >= 0) { if (ObVal(self->ParArray, FIX) >= 0) {
sprintf(pBueffel, "Motor %s is Fixed", self->name); snprintf(pError, iErrLen, "Motor %s is Fixed", self->name);
strncpy(pError, pBueffel, iErrLen);
return 0; /* is this an error? */ return 0; /* is this an error? */
} }
/* check against software boundaries */ /* check against software boundaries */
if (fVal > ObVal(self->ParArray, SUPP)) { if (fVal > ObVal(self->ParArray, SUPP)) {
sprintf(pBueffel, "%f violates upper software limit %f on %s", snprintf(pError, iErrLen, "%g violates upper software limit %g on %s",
fVal, ObVal(self->ParArray, SUPP), self->name); fVal, ObVal(self->ParArray, SUPP), self->name);
strncpy(pError, pBueffel, iErrLen);
return 0; return 0;
} }
if (fVal < ObVal(self->ParArray, SLOW)) { if (fVal < ObVal(self->ParArray, SLOW)) {
sprintf(pBueffel, "%f violates lower software limit %f on %s", snprintf(pError, iErrLen, "%g violates lower software limit %g on %s",
fVal, ObVal(self->ParArray, SLOW), self->name); fVal, ObVal(self->ParArray, SLOW), self->name);
strncpy(pError, pBueffel, iErrLen);
return 0; return 0;
} }
@ -163,15 +160,17 @@ static int MotorCheckBoundaryImpl(pMotor self, float fVal, float *fNew,
/* check for hardware limits */ /* check for hardware limits */
if (fHard > self->pDriver->fUpper) { if (fHard > self->pDriver->fUpper) {
sprintf(pBueffel, "%f violates upper hardware limit %f on %s", fLim = self->pDriver->fUpper * ObVal(self->ParArray,SIGN) + fZero;
fVal, self->pDriver->fUpper, self->name); snprintf(pError, iErrLen,
strncpy(pError, pBueffel, iErrLen); "%g violates upper hardware limit %g (%g) on %s",
fVal, fLim, self->pDriver->fUpper, self->name);
return 0; return 0;
} }
if (fHard < self->pDriver->fLower) { if (fHard < self->pDriver->fLower) {
sprintf(pBueffel, "%f violates lower hardware limit %f on %s", fLim = self->pDriver->fLower * ObVal(self->ParArray,SIGN) + fZero;
fVal, self->pDriver->fLower, self->name); snprintf(pError, iErrLen,
strncpy(pError, pBueffel, iErrLen); "%g violates lower hardware limit %g (%g) on %s",
fVal, fLim, self->pDriver->fLower, self->name);
return 0; return 0;
} }

View File

@ -51,6 +51,8 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include "sics.h"
#include "commandlog.h"
#include "uselect.h" #include "uselect.h"
#define PORT 1 #define PORT 1
@ -65,11 +67,6 @@ struct timeval lastclose = { -1, 0 };
/*----------------------------------------------------------------------- /*-----------------------------------------------------------------------
Redefine this function if another means of error reporting is necessary. Redefine this function if another means of error reporting is necessary.
*/ */
#include "Scommon.h"
extern void SICSLogWrite(char *pText, OutCode eCode); /* servlog.c */
void WriteToCommandLog(char *p, char *t);
static void NetError(char *pText) static void NetError(char *pText)
{ {
/* /*
@ -674,8 +671,44 @@ int NETReadTillTerm(mkChannel * self, long timeout,
status = NETAvailable(self, timeout - dif); status = NETAvailable(self, timeout - dif);
}; };
}; };
assert(bufPtr > 0); return status;
return bufPtr; }
/*-------------------------------------------------------------------------*/
int NETReadRemob(mkChannel * self, long timeout, long timeout2,
char term, char *pBuffer, int iBufLen)
{
struct timeval start, now;
int bufPtr = 0, status, i, length, matchIndex = 1;
char c;
long dif;
if (!VerifyChannel(self)) {
return -1;
}
memset(pBuffer, 0, iBufLen);
status = NETAvailable(self, timeout);
while (status > 0) {
status = recv(self->sockid, &c, 1, 0);
if (status <= 0) {
return status;
}
if (c == term) {
return bufPtr + 1;
}
if (bufPtr >= iBufLen - 1) {
return -1; /* overflow */
}
pBuffer[bufPtr] = c;
bufPtr++;
/*
wait for more data
*/
status = NETAvailable(self, timeout2);
};
return status;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -701,7 +734,7 @@ int NETClosePort(mkChannel * self)
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
int NETReconnectWithFlags(mkChannel * self, int flags) int NETReconnectWithFlags(mkChannel * self, int flags)
{ {
int iRet; int iRet = 0;
int sock; int sock;
int oldopts; int oldopts;
@ -709,7 +742,9 @@ int NETReconnectWithFlags(mkChannel * self, int flags)
* Get the flags and close the old socket * Get the flags and close the old socket
*/ */
oldopts = fcntl(self->sockid, F_GETFL, 0); oldopts = fcntl(self->sockid, F_GETFL, 0);
close(self->sockid); if (self->sockid != 0) {
close(self->sockid);
}
/* Reopen and try to get it on the olf fd */ /* Reopen and try to get it on the olf fd */
sock = socket(AF_INET, SOCK_STREAM, 0); sock = socket(AF_INET, SOCK_STREAM, 0);
if (self->sockid != sock) { if (self->sockid != sock) {

View File

@ -63,7 +63,7 @@ mkChannel *NETConnectWithFlags(char *name, int port, int flags);
if (flags & 1): do not block on connect (use NETConnectFinished if (flags & 1): do not block on connect (use NETConnectFinished
to check success) to check success)
if (flags & 2): wait 1000 ms after last close (workaround for if (flags & 2): wait 1000 ms after last close (workaround for
a bug in Lantronix terminal server a bug in the Lantronix terminal server)
*/ */
int NETConnectFinished(mkChannel * self); int NETConnectFinished(mkChannel * self);
@ -91,8 +91,8 @@ int NETReconnectWithFlags(mkChannel * self, int flags);
/* *********************** DATA TRANSFER ******************************** */ /* *********************** DATA TRANSFER ******************************** */
int NETWrite(mkChannel * self, char *buffer, long lLen); int NETWrite(mkChannel * self, char *buffer, long lLen);
/* writes data to socket self, returns True if success, /* writes data to socket self, returns 1 if success,
false otherwise. 0 otherwise.
*/ */
long NETRead(mkChannel * self, char *buffer, long lLen, long timeout); long NETRead(mkChannel * self, char *buffer, long lLen, long timeout);
@ -122,6 +122,9 @@ int NETReadTillTerm(mkChannel * self, long timeout,
If no terminator is given, the routine waits for iBufLen characters If no terminator is given, the routine waits for iBufLen characters
or timeout. or timeout.
*/ */
int NETReadRemob(mkChannel *self, long timeout, long timeout2,
char term, char *pBuffer, int iBufLen);
/* special version for remob */
/* ********************* KILLING FIELD ******************************** */ /* ********************* KILLING FIELD ******************************** */
int NETClosePort(mkChannel * self); int NETClosePort(mkChannel * self);
/* closes a port, do not forget to free the channel data- /* closes a port, do not forget to free the channel data-

View File

@ -448,7 +448,7 @@ int UserWait(SConnection * pCon, SicsInterp * pSics, void *pData,
if (i < 1) { if (i < 1) {
sprintf(pBueffel, "Expected numeric argument to %s, got %s", sprintf(pBueffel, "Expected numeric argument to %s, got %s",
argv[0], argv[1]); argv[0], argv[1]);
SCWrite(pCon, pBueffel, eInError); SCWrite(pCon, pBueffel, eError);
return 0; return 0;
} }

5
ofac.c
View File

@ -236,6 +236,7 @@ static void InitIniCommands(SicsInterp * pInter, pTaskMan pTask)
AddCommand(pInter, "SICSStatus", SICSStatus, NULL, NULL); AddCommand(pInter, "SICSStatus", SICSStatus, NULL, NULL);
AddCommand(pInter, "sicstime", SICSTime, NULL, NULL); AddCommand(pInter, "sicstime", SICSTime, NULL, NULL);
AddCommand(pInter, "sicsdescriptor", SICSDescriptor, NULL, NULL); AddCommand(pInter, "sicsdescriptor", SICSDescriptor, NULL, NULL);
AddCommand(pInter, "silent", SICSSilent, NULL, NULL);
AddCommand(pInter, "SetStatus", SetSICSStatus, NULL, NULL); AddCommand(pInter, "SetStatus", SetSICSStatus, NULL, NULL);
AddCommand(pInter, "db", SICSDebug, NULL, NULL); AddCommand(pInter, "db", SICSDebug, NULL, NULL);
AddCommand(pInter, "EVFactory", EVControlFactory, NULL, NULL); AddCommand(pInter, "EVFactory", EVControlFactory, NULL, NULL);
@ -439,7 +440,9 @@ void InitGeneral(void)
INIT(InitializerInit); INIT(InitializerInit);
INIT(SaveHdbInit); /* must be after InitializerInit */ INIT(SaveHdbInit); /* must be after InitializerInit */
INIT(SctInit); INIT(SctInit);
INIT(SctDriveInit); INIT(SctDriveAdapterInit);
INIT(SctDriveObjInit);
INIT(SctDriveAdapterInit);
INIT(LogReaderInit); INIT(LogReaderInit);
INIT(LogSetupInit); INIT(LogSetupInit);
INIT(StatusFileInit); INIT(StatusFileInit);

View File

@ -485,7 +485,6 @@ int SicsPrompt(SConnection * pCon, SicsInterp * pSics, void *pData,
/*----------------------- get object descriptor name ------------------------------- /*----------------------- get object descriptor name -------------------------------
get the name of the object descriptor get the name of the object descriptor
*/ */
int SICSDescriptor(SConnection * pCon, SicsInterp * pSics, void *pData, int SICSDescriptor(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[]) int argc, char *argv[])
{ {
@ -517,3 +516,44 @@ int SICSDescriptor(SConnection * pCon, SicsInterp * pSics, void *pData,
SCWrite(pCon, "notfound", eValue); SCWrite(pCon, "notfound", eValue);
return 1; return 1;
} }
/*------------------------------------------------------------------------*/
int SICSSilent(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]) {
Tcl_Interp *pTcl = NULL;
int iRet;
char *cmd;
char *result;
writeFunc oldWrite;
assert(pCon);
assert(pSics);
if (!SCinMacro(pCon)) {
SCPrintf(pCon, eError,
"ERROR: %s may only be called in scripts", argv[0]);
return 0;
}
pTcl = InterpGetTcl(pSics);
assert(pTcl);
if (argc < 3) {
SCWrite(pCon, "ERROR: should be: silent <error-value> <tcl-command>", eError);
return 0;
}
cmd = Arg2Tcl(argc-2,&argv[2],NULL,0);
assert(cmd);
oldWrite = SCGetWriteFunc(pCon);
SCSetWriteFunc(pCon,SCNotWrite);
iRet = Tcl_EvalEx(pTcl, cmd, strlen(cmd), 0);
SCSetWriteFunc(pCon,oldWrite);
if (iRet == TCL_OK) {
result = strdup((char *)Tcl_GetStringResult(pTcl));
SCWrite(pCon, result, eValue);
free(result);
} else {
SCWrite(pCon, argv[1], eValue);
}
free(cmd);
return 1;
}

View File

@ -48,4 +48,7 @@ int SicsPrompt(SConnection * pCon, SicsInterp * pSics, void *pData,
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
int SICSDescriptor(SConnection * pCon, SicsInterp * pSics, void *pData, int SICSDescriptor(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
/*----------------------------------------------------------------------*/
int SICSSilent(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif #endif

View File

@ -47,7 +47,7 @@ typedef struct SctData {
} SctData; } SctData;
static ScriptContext *sct = NULL; static ScriptContext *sct = NULL;
static SConnection *currentCon = NULL; static SctData *queueData = NULL;
static struct { static struct {
char *name; char *name;
@ -179,6 +179,7 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
return 0; return 0;
} }
UpdateHipadabaPar(node, v, con); UpdateHipadabaPar(node, v, con);
ReleaseHdbValue(&v);
SetHdbProperty(node, "geterror", NULL); SetHdbProperty(node, "geterror", NULL);
return 1; return 1;
} }
@ -187,6 +188,9 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
* print * print
*/ */
if (strcmp(argv[1], "print") == 0) { if (strcmp(argv[1], "print") == 0) {
if (queueData != NULL) {
queueData->answered = 1;
}
Arg2Text(argc - 2, argv + 2, value, sizeof value); Arg2Text(argc - 2, argv + 2, value, sizeof value);
SCWrite(con, value, eLog); SCWrite(con, value, eLog);
return 1; return 1;
@ -201,7 +205,7 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
} }
/* /*
* time stamping * time stamping (obsolete ? -> see SctActionHandler: timeKey, timeVal)
*/ */
if (strcmp(argv[1], "utime") == 0) { if (strcmp(argv[1], "utime") == 0) {
if (argc < 3) { if (argc < 3) {
@ -248,7 +252,7 @@ int SctCallInContext(SConnection * con, char *script, Hdb * node,
PushContext(node, controller->node); PushContext(node, controller->node);
if (verbose) { if (verbose) {
SCPrintf(con, eLog, "\nscript: %s\n", script); SCPrintf(con, eLog, "script: %s", script);
} }
MacroPush(con); MacroPush(con);
@ -257,7 +261,7 @@ int SctCallInContext(SConnection * con, char *script, Hdb * node,
result = (char *) Tcl_GetStringResult(pTcl); result = (char *) Tcl_GetStringResult(pTcl);
if (ret != TCL_OK && result[0] != '\0') { if (ret != TCL_OK && result[0] != '\0') {
if (verbose) { if (verbose) {
SCPrintf(con, eLog, "\nerror: %s\n", result); SCPrintf(con, eLog, "error: %s", result);
} }
iRet = 0; iRet = 0;
} }
@ -276,26 +280,38 @@ 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;
} }
static char *SctActionHandler(void *actionData, char *lastReply) static char *SctActionHandler(void *actionData, char *lastReply,
int commError)
{ {
SctData *data = actionData; SctData *data = actionData;
Hdb *node = data->node; Hdb *node = data->node;
SctController *controller = data->controller; SctController *controller = data->controller;
char *state; char *state;
char *result; char *result;
char *script; char *script = NULL;
char *errorScript = NULL;
char *send = NULL; char *send = NULL;
int i; int i;
SConnection *con; SConnection *con;
char eprop[80];
char msg[1024];
char path[1024];
char origScript[80];
char *blank;
char *emsg;
size_t l;
int cnt;
char timeKey[50], timeVal[50]; char timeKey[50], timeVal[50];
if (currentCon) { if (queueData != NULL && queueData->conCtx != NULL) {
con = currentCon; con = queueData->conCtx;
} else { } else {
con = controller->conn; con = controller->conn;
} }
SetProp(node, controller->node, "result", lastReply); SetProp(node, controller->node, "result", lastReply);
if (controller->verbose && lastReply != NULL && *lastReply != '\0') { script = NULL;
if (!commError && controller->verbose && lastReply != NULL
&& *lastReply != '\0') {
SCPrintf(con, eLog, "reply : %s", lastReply); SCPrintf(con, eLog, "reply : %s", lastReply);
} }
state = GetProp(node, controller->node, "state"); state = GetProp(node, controller->node, "state");
@ -304,29 +320,75 @@ static char *SctActionHandler(void *actionData, char *lastReply)
SetProp(node, controller->node, "state", state); SetProp(node, controller->node, "state", state);
} }
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
SetProp(node, controller->node, "sent",
GetProp(node, controller->node, "send"));
SetProp(node, controller->node, "send", NULL); SetProp(node, controller->node, "send", NULL);
script = GetProp(node, controller->node, state); script = GetProp(node, controller->node, state);
if (script == NULL) if (script == NULL)
script = state; script = state;
snprintf(origScript, sizeof origScript, "%s", script);
if (commError) {
errorScript = GetProp(node, controller->node, "commerror");
if (errorScript != NULL)
script = errorScript;
commError = 0;
}
script = strdup(script);
if (!SctCallInContext(con, script, node, data->controller, &result)) { if (!SctCallInContext(con, script, node, data->controller, &result)) {
SCPrintf(con, eError, "ERROR: %s", result); snprintf(eprop, sizeof eprop, "error_during_%s", data->name);
if (strncmp(result, "ERROR: ", 7) == 0) {
result += 7;
}
emsg = GetHdbProp(node, eprop);
if (emsg == NULL) {
GetHdbPath(node, path, sizeof path);
SCPrintf(con, eError,
"ERROR: action <%s> in {%s} node %s:\nERROR: %s",
data->name, origScript, path, result);
}
snprintf(msg, sizeof msg, "<%s> %s", origScript, result);
SetHdbProperty(node, eprop, msg);
blank = strchr(origScript, ' ');
if (blank != NULL) {
l = blank - origScript;
} else {
l = strlen(origScript);
}
snprintf(eprop, sizeof eprop, "error_in_%.*s", l, origScript);
emsg = GetHdbProp(node, eprop);
cnt = 0;
if (emsg != NULL) {
sscanf(emsg, "%d", &cnt);
}
cnt++;
snprintf(msg, sizeof msg, "%dx {%s} %s", cnt, origScript, result);
SetHdbProperty(node, eprop, msg);
send = NULL;
goto finish; goto finish;
} }
state = result; state = result;
if (strcasecmp(state, "idle") == 0) { if (strcasecmp(state, "idle") == 0 || strcasecmp(state, "unpoll") == 0) {
if (currentCon && !data->answered) { if (queueData == data && !data->answered) {
SCWrite(con, "o.k.", eValue); SCWrite(con, "o.k.", eStatus);
} }
if (strcmp(data->name, "write") == 0) { snprintf(eprop, sizeof eprop, "error_during_%s", data->name);
SetHdbProperty(data->node, "writestatus", "commandsent"); emsg = GetHdbProp(node, eprop);
if (emsg != NULL) {
GetHdbPath(node, path, sizeof path);
SCPrintf(con, eError,
"action <%s>: success after error message (%s)\n %s",
data->name, path, emsg);
SetHdbProperty(node, eprop, NULL);
} }
snprintf(timeKey, 50, "%s_time", data->name); snprintf(timeKey, sizeof timeKey, "%s_time", data->name);
snprintf(timeVal, 50, "%.3f", DoubleTime()); snprintf(timeVal, sizeof timeVal, "%.3f", DoubleTime());
SetHdbProperty(data->node, timeKey, timeVal); SetHdbProperty(data->node, timeKey, timeVal);
send = NULL;
goto finish; goto finish;
} }
SetProp(node, controller->node, "state", state); SetProp(node, controller->node, "state", state);
free(script);
script = NULL;
send = GetProp(node, controller->node, "send"); send = GetProp(node, controller->node, "send");
if (send != NULL && send[0] != '\0') { if (send != NULL && send[0] != '\0') {
if (controller->verbose) { if (controller->verbose) {
@ -337,6 +399,16 @@ static char *SctActionHandler(void *actionData, char *lastReply)
} }
SCPrintf(con, eLogError, "ERROR: too many quick scripts chained"); SCPrintf(con, eLogError, "ERROR: too many quick scripts chained");
finish: finish:
if (strcmp(data->name, "write") == 0) {
/* check if it would be ok to do this only when writestatus property exists:
GetHdbProp(data->node, "writestatus") != NULL
*/
SetHdbProperty(data->node, "writestatus", "commandsent");
}
if (strcasecmp(state, "unpoll") == 0) {
DevUnschedule(controller->devser, data, SctActionHandler, SctMatch);
send = NULL;
}
SetProp(node, controller->node, "state", "idle"); SetProp(node, controller->node, "state", "idle");
if (data->conCtx != NULL) { if (data->conCtx != NULL) {
SCDeleteConnection(data->conCtx); SCDeleteConnection(data->conCtx);
@ -345,16 +417,17 @@ finish:
return send; return send;
} }
static char *SctWriteHandler(void *actionData, char *lastReply) static char *SctWriteHandler(void *actionData, char *lastReply,
int commError)
{ {
SctData *data = actionData; SctData *data = actionData;
SConnection *old; SctData *old;
char *result; char *result;
old = currentCon; old = queueData;
currentCon = data->conCtx; queueData = data;
result = SctActionHandler(data, lastReply); result = SctActionHandler(data, lastReply, commError);
currentCon = old; queueData = old;
return result; return result;
} }
@ -379,6 +452,10 @@ static hdbCallbackReturn SctMainCallback(Hdb * node, void *userData,
char *geterror; char *geterror;
char error[256]; char error[256];
if (controller->devser == NULL) {
/* defunct controller */
return hdbContinue;
}
pm = GetKillPtrMessage(msg); pm = GetKillPtrMessage(msg);
if (pm != NULL) { if (pm != NULL) {
if (controller == pm->pPtr) { if (controller == pm->pPtr) {
@ -440,7 +517,6 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData,
char *writeprio; char *writeprio;
char *error; char *error;
SConnection *con; SConnection *con;
SConnection *con2;
char path[MAX_HDB_PATH]; char path[MAX_HDB_PATH];
pm = GetKillPtrMessage(msg); pm = GetKillPtrMessage(msg);
@ -510,16 +586,16 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData,
mm = GetHdbUpdateMessage(msg); mm = GetHdbUpdateMessage(msg);
if (mm != NULL) { if (mm != NULL) {
if (currentCon) { /* update called from a write action */ if (queueData != NULL && queueData->conCtx != NULL && !data->answered) {
/* update called from a write action */
data->answered = 1; data->answered = 1;
GetHdbPath(node, path, sizeof path); GetHdbPath(node, path, sizeof path);
con = currentCon;
text = formatValue(*(mm->v), node); text = formatValue(*(mm->v), node);
/* Markus: who is receiving this message? /* Markus: who is receiving this message?
It gave unwanted output to me. MK It gave unwanted output to me. MK
SCPrintf(con, eLog, "%s = %s", path, GetCharArray(text)); Answer: a commandline client -> outcode eStatus correct?
*/ */
SCPrintf(queueData->conCtx, eStatus, "%s = %s", path, GetCharArray(text));
DeleteDynString(text); DeleteDynString(text);
} }
return hdbContinue; return hdbContinue;
@ -577,7 +653,9 @@ static void SctKillCBData(void *d)
{ {
SctData *data = d; SctData *data = d;
DevRemoveAction(data->controller->devser, data); if (data->controller->devser != NULL) {
DevRemoveAction(data->controller->devser, data);
}
SctKillData(d); SctKillData(d);
} }
@ -866,7 +944,8 @@ static void KillSctTransact(void *data)
free(self); free(self);
} }
static char *TransactionHandler(void *actionData, char *lastReply) static char *TransactionHandler(void *actionData, char *lastReply,
int commError)
{ {
pSctTransact st = (pSctTransact) actionData; pSctTransact st = (pSctTransact) actionData;
@ -976,6 +1055,12 @@ static hdbCallbackReturn SctDebugCallback(Hdb * node, void *userData,
return hdbContinue; return hdbContinue;
} }
static int SctDeferredFree(void *data)
{
free(data);
return 0;
}
static void SctKillController(void *c) static void SctKillController(void *c)
{ {
SctController *controller = c; SctController *controller = c;
@ -987,7 +1072,13 @@ static void SctKillController(void *c)
SCDeleteConnection(controller->conn); SCDeleteConnection(controller->conn);
} }
DevKill(controller->devser); DevKill(controller->devser);
free(controller); controller->devser = NULL;
if (pServ->pTasker) {
TaskRegister(pServ->pTasker, SctDeferredFree, NULL, NULL, controller,
0);
} else {
free(controller);
}
} }
static int SctMakeController(SConnection * con, SicsInterp * sics, static int SctMakeController(SConnection * con, SicsInterp * sics,
@ -995,33 +1086,33 @@ static int SctMakeController(SConnection * con, SicsInterp * sics,
{ {
SICSOBJ *ccmd; SICSOBJ *ccmd;
Hdb *parent, *par, *cmd; Hdb *parent, *par, *cmd;
char *nodeName; char *objName;
hdbCallback *cb; hdbCallback *cb;
SctController *controller; SctController *controller;
if (argc < 2) { if (argc < 2) {
SCPrintf(con, eError, SCPrintf(con, eError,
"ERROR: should be %s <path> <protocol args> ...", argv[0]); "ERROR: should be %s <path or objectname> <protocol args> ...",
argv[0]);
return 0; return 0;
} }
/* if (strchr(argv[1], '/') == NULL) {
* Install into the Hipadaba when full path given /* object name only -> do not anchor in tree */
*/ parent = NULL;
if(strstr(argv[1],"/") != NULL){ objName = argv[1];
parent = FindHdbParent(NULL, argv[1], &nodeName, con);
if (parent == NULL)
return 0; /* error message already written */
} else { } else {
nodeName = argv[1]; /* full path given -> install into the hipadaba */
parent = NULL; parent = FindHdbParent(NULL, argv[1], &objName, con);
if (parent == NULL)
return 0; /* error message already written */
} }
controller = calloc(1, sizeof(*controller)); controller = calloc(1, sizeof(*controller));
assert(controller); assert(controller);
controller->verbose = 0; controller->verbose = 0;
ccmd = MakeSICSOBJv(nodeName, "SctController", HIPNONE, usSpy); ccmd = MakeSICSOBJv(objName, "SctController", HIPNONE, usSpy);
controller->node = ccmd->objectNode; controller->node = ccmd->objectNode;
controller->conn = SCCreateDummyConnection(pServ->pSics); controller->conn = SCCreateDummyConnection(pServ->pSics);
@ -1030,15 +1121,16 @@ static int SctMakeController(SConnection * con, SicsInterp * sics,
ccmd->pPrivate = controller; ccmd->pPrivate = controller;
ccmd->KillPrivate = SctKillController; ccmd->KillPrivate = SctKillController;
if(parent != NULL){ if (parent != NULL) {
AddHipadabaChild(parent, controller->node, con); AddHipadabaChild(parent, controller->node, con);
} }
controller->devser = DevMake(con, argc - 2, argv + 2); controller->devser = DevMake(con, argc - 2, argv + 2);
if (!controller->devser) if (!controller->devser)
return 0; return 0;
AddCommand(pServ->pSics, nodeName, InvokeSICSOBJ, KillSICSOBJ, ccmd); AddCommand(pServ->pSics, objName, InterInvokeSICSOBJ, KillSICSOBJ, ccmd);
RegisterSICSOBJKillCmd(ccmd, objName);
SetDescriptorKey(ccmd->pDes, "creationCommand", "0"); SetDescriptorKey(ccmd->pDes, "creationCommand", "0");
cmd = AddSICSHdbPar(controller->node, cmd = AddSICSHdbPar(controller->node,

View File

@ -306,8 +306,9 @@ int SctMakeDriveAdapter(SConnection * pCon, SicsInterp * pSics,
} }
if (argc < 4) { if (argc < 4) {
SCWrite(pCon, "ERROR: not enough arguments for SctMakeDriveAdapter", SCPrintf(pCon, eError,
eError); "ERROR: should be %s <object name> <existing-node> <controller>",
argv[0]);
return 0; return 0;
} }
@ -335,12 +336,8 @@ int SctMakeDriveAdapter(SConnection * pCon, SicsInterp * pSics,
} }
/*---------------------------------------------------------------*/ /*---------------------------------------------------------------*/
int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics, void SctDriveAdapterInit(void)
void *object, int argc, char *argv[]);
void SctDriveInit(void)
{ {
AddCmd("makesctdrive", SctMakeDriveAdapter); AddCmd("makesctdrive", SctMakeDriveAdapter);
AddCmd("dynsctdrive", SctMakeDriveAdapter); AddCmd("dynsctdrive", SctMakeDriveAdapter);
AddCmd("makesctdriveobj", SctMakeDriveObject);
} }

View File

@ -3,6 +3,19 @@
* scriptcontext to control the actual driving operation. This can also * scriptcontext to control the actual driving operation. This can also
* serve as a drivable adapter to nodes in other objects. * serve as a drivable adapter to nodes in other objects.
* *
* Some cooperation from the node is required: It has to provide
* certain properties the value of which define scripts which
* have to be called at various stages. These are:
*
* checklimits, for limits checking
* checkstatus, for evaluating progress
* halt , for halting things
*
* If no checklimits script is given, nothing is checked.
* If no checkstatus scripts is given, the value of the status property is
* returned. In that case the status value should be updated by some poll script.
* If no halt script is given, the status is set to idle. M.Z. Sept. 08
*
* copyright: see file COPYRIGHT * copyright: see file COPYRIGHT
* *
* Mark Koennecke, June-July 2008 * Mark Koennecke, June-July 2008
@ -22,18 +35,19 @@ typedef struct {
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
static void KillDrivePriv(void *data) static void KillDrivePriv(void *data)
{ {
pDrivObjPriv priv = (pDrivObjPriv)data; pDrivObjPriv priv = (pDrivObjPriv) data;
if(priv == NULL){ if (priv == NULL) {
return; return;
} }
if(priv->pDriv != NULL){ if (priv->pDriv != NULL) {
free(priv->pDriv); free(priv->pDriv);
} }
if(priv->pCon != NULL){ if (priv->pCon != NULL) {
SCDeleteConnection(priv->pCon); SCDeleteConnection(priv->pCon);
} }
free(priv); free(priv);
} }
/*---------------------------------------------------------------*/ /*---------------------------------------------------------------*/
static void *SCTDRIVGetInterface(void *data, int iD) static void *SCTDRIVGetInterface(void *data, int iD)
{ {
@ -65,8 +79,8 @@ static int SCTDRIVHalt(void *data)
self = (pSICSOBJ) data; self = (pSICSOBJ) data;
pPriv = (pDrivObjPriv) self->pPrivate; pPriv = (pDrivObjPriv) self->pPrivate;
if (GetHdbProperty(self->objectNode, "halt", dummy, sizeof dummy)) { if (GetHdbProperty(self->objectNode, "halt", dummy, sizeof dummy)) {
SctQueueNode(pPriv->c, self->objectNode, HaltPRIO, "halt", SctQueueNode(pPriv->c, self->objectNode, HaltPRIO, "halt",
pPriv->pCon); pPriv->pCon);
} else } else
if (GetHdbProperty(self->objectNode, "status", dummy, sizeof dummy)) if (GetHdbProperty(self->objectNode, "status", dummy, sizeof dummy))
{ {
@ -128,11 +142,13 @@ static long SCTDRIVSetValue(void *data, SConnection * pCon, float val)
self = (pSICSOBJ) data; self = (pSICSOBJ) data;
pPriv = (pDrivObjPriv) self->pPrivate; pPriv = (pDrivObjPriv) self->pPrivate;
if(pPriv->pCon != NULL){ if (pPriv->pCon != NULL) {
SCDeleteConnection(pPriv->pCon); SCDeleteConnection(pPriv->pCon);
} }
pPriv->pCon = SCCopyConnection(pCon); pPriv->pCon = SCCopyConnection(pCon);
StopByData(pServ->pExecutor, data);
v.dataType = HIPFLOAT; v.dataType = HIPFLOAT;
v.v.doubleValue = (double) val; v.v.doubleValue = (double) val;
SetHdbProperty(self->objectNode, "writestatus", "start"); SetHdbProperty(self->objectNode, "writestatus", "start");
@ -258,24 +274,17 @@ static void KillDriveOBJ(void *data)
} }
pPriv = (pDrivObjPriv) self->pPrivate; pPriv = (pDrivObjPriv) self->pPrivate;
if (pPriv->doNotKillNode && self->pDes != NULL) { if (pPriv->doNotKillNode && GetDescriptorKey(self->pDes, "creationCommand") == NULL /* it's not a dynamic object */
if (self->pDes->name) && self->pDes != NULL) {
free(self->pDes->name); self->objectNode = NULL; /* do not call RemoveHdbNodeFromParent in KillSICSOBJ */
if (self->pDes->pKeys) self->pDes->parNode = NULL; /* do not kill the node in KillSICSOBJ/DeleteDescriptor */
IFDeleteOptions(self->pDes->pKeys);
free(self->pDes);
} else {
DeleteDescriptor(self->pDes); /* kill descriptor including node */
} }
if (self->KillPrivate != NULL && self->pPrivate != NULL) { KillSICSOBJ(self);
self->KillPrivate(self->pPrivate);
}
RemoveHdbNodeFromParent(self->objectNode, pServ->dummyCon);
free(self);
} }
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController * c) pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController * c,
int doNotKillNode)
{ {
pSICSOBJ pNew = NULL; pSICSOBJ pNew = NULL;
pDrivObjPriv pPriv = NULL; pDrivObjPriv pPriv = NULL;
@ -299,6 +308,7 @@ pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController * c)
pNew->objectNode = node; pNew->objectNode = node;
AssignSctDrive(pPriv->pDriv); AssignSctDrive(pPriv->pDriv);
pPriv->c = c; pPriv->c = c;
pPriv->doNotKillNode = doNotKillNode;
pNew->pDes->parNode = pNew->objectNode; pNew->pDes->parNode = pNew->objectNode;
pNew->pDes->GetInterface = SCTDRIVGetInterface; pNew->pDes->GetInterface = SCTDRIVGetInterface;
pNew->pPrivate = pPriv; pNew->pPrivate = pPriv;
@ -309,7 +319,7 @@ pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController * c)
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
* This actually has two syntaxes: * This actually has two syntaxes:
* makesctdrive name path-to-existing-node class SctController * makesctdrive name path-to-existing-node class SctController
* makesctdrive name type priv class SctController * makesctdrive name float priv class SctController
*--------------------------------------------------------------------------*/ *--------------------------------------------------------------------------*/
int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics, int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics,
void *object, int argc, char *argv[]) void *object, int argc, char *argv[])
@ -319,54 +329,58 @@ int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics,
pSICSOBJ pNew = NULL; pSICSOBJ pNew = NULL;
pSICSOBJ pSct = NULL; pSICSOBJ pSct = NULL;
SctController *c = NULL; SctController *c = NULL;
int priv, type, status; int priv, type, status, doNotKillNode;
hdbValue val; hdbValue val;
char *sctName;
char *class;
if (argc < 5) { if (argc < 5)
SCWrite(pCon, "ERROR: not enough arguments to SctMakeDriveObject", goto Usage;
eError);
return 0;
}
node = FindHdbNode(NULL, argv[2], pCon); if (argc == 5) {
if (node != NULL) { node = FindHdbNode(NULL, argv[2], pCon);
pSct = FindCommandData(pSics, argv[4], "SctController"); if (node == NULL) {
if (pSct == NULL) { SCPrintf(pCon, eError, "ERROR: node %s not found", argv[2]);
SCPrintf(pCon, eError, "ERROR: SctController %s not found", argv[4]); goto Usage;
return 0;
} }
c = (SctController *) pSct->pPrivate; sctName = argv[4];
pNew = MakeSctDriveObj(node, argv[3], c); class = argv[3];
pPriv = (pDrivObjPriv) pNew->pPrivate; doNotKillNode = 1; /* the node is owned by someone else */
pPriv->doNotKillNode = 1; /* the node is owned by someone else */
} else { } else {
/* convert datatype */
type = convertHdbType(argv[2]);
/* convert privilege */ /* convert privilege */
priv = decodeSICSPriv(argv[3]); priv = decodeSICSPriv(argv[3]);
/* convert datatype */ if (priv < 0 || type != HIPFLOAT)
strtolower(argv[4]); goto Usage;
type = convertHdbType(argv[2]); node = MakeSICSHdbPar(argv[1], priv, MakeHdbFloat(0.0));
if (type == HIPNONE) {
node = MakeHipadabaNode(argv[1], HIPNONE, 1);
} else {
val = makeHdbValue(type, 0);
node = MakeSICSHdbPar(argv[1], priv, val);
ReleaseHdbValue(&val);
}
if (node == NULL) { if (node == NULL) {
SCWrite(pCon, "ERROR: node creation failed", eError); SCWrite(pCon, "ERROR: node creation failed", eError);
return 0; return 0;
} }
c = FindCommandData(pSics, argv[5], "SctController"); sctName = argv[5];
if (c == NULL) { class = argv[4];
SCPrintf(pCon, eError, "ERROR: SctController %s not found", argv[4]); doNotKillNode = 0; /* kill the node with the command */
return 0;
}
pNew = MakeSctDriveObj(node, argv[3], c);
} }
pSct = FindCommandData(pSics, sctName, "SctController");
if (pSct == NULL) {
SCPrintf(pCon, eError, "ERROR: SctController %s not found", sctName);
goto Usage;
}
c = (SctController *) pSct->pPrivate;
pNew = MakeSctDriveObj(node, class, c, doNotKillNode);
SetHdbProperty(node, "objectName", argv[1]);
if (pNew == NULL) { if (pNew == NULL) {
SCWrite(pCon, "ERROR: failed to create drive object", eError); SCWrite(pCon, "ERROR: failed to create drive object", eError);
return 0; return 0;
} }
if (strcasecmp(argv[0], "dynsctdriveobj") == 0) {
/* make object dynamic by defining a creation command */
SetDescriptorKey(pNew->pDes, "creationCommand", "0");
RegisterSICSOBJKillCmd(pNew, argv[1]);
}
status = AddCommand(pSics, status = AddCommand(pSics,
argv[1], InterInvokeSICSOBJ, KillDriveOBJ, pNew); argv[1], InterInvokeSICSOBJ, KillDriveOBJ, pNew);
if (status != 1) { if (status != 1) {
@ -376,4 +390,18 @@ int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics,
return 0; return 0;
} }
return 1; return 1;
Usage:
SCPrintf(pCon, eError,
"ERROR: should be %s <object name> <existing node> <class> <controller>",
argv[0]);
SCPrintf(pCon, eError,
"ERROR: or %s <object name> <type> <priv> <class> <controller>",
argv[0]);
return 0;
}
/*---------------------------------------------------------------*/
void SctDriveObjInit(void)
{
AddCmd("makesctdriveobj", SctMakeDriveObject);
AddCmd("dynsctdriveobj", SctMakeDriveObject);
} }

View File

@ -1346,6 +1346,7 @@ static void SICSDeleteNodeData(pHdb node)
} }
removeNodeFromUpdateList(node); removeNodeFromUpdateList(node);
DeleteCallbackChain(node);
while (node->child != NULL) { while (node->child != NULL) {
tmp = node->child; tmp = node->child;
node->child = node->child->next; node->child = node->child->next;
@ -1354,7 +1355,6 @@ static void SICSDeleteNodeData(pHdb node)
if (node->properties != NULL) { if (node->properties != NULL) {
DeleteStringDict(node->properties); DeleteStringDict(node->properties);
} }
DeleteCallbackChain(node);
if (node->name != NULL) { if (node->name != NULL) {
free(node->name); free(node->name);
@ -1616,7 +1616,7 @@ static int RemoveParNodeCallback(char *name, pDummy object,
m.type = killPtr; m.type = killPtr;
m.pPtr = internalID; m.pPtr = internalID;
if (object->pDescriptor->parNode) { if (object && object->pDescriptor->parNode) {
RecurseCallbackChains(object->pDescriptor->parNode, (pHdbMessage) & m); RecurseCallbackChains(object->pDescriptor->parNode, (pHdbMessage) & m);
} }
return 1; return 1;
@ -1805,7 +1805,8 @@ int ProcessSICSHdbPar(pHdb root, SConnection * pCon,
SCWrite(pCon, "ERROR: out of memory processing parameter", eError); SCWrite(pCon, "ERROR: out of memory processing parameter", eError);
return 0; return 0;
} }
for (i = 1; i < argc; i++) { DynStringConcat(parData, argv[1]);
for (i = 2; i < argc; i++) {
DynStringConcat(parData, " "); DynStringConcat(parData, " ");
DynStringConcat(parData, argv[i]); DynStringConcat(parData, argv[i]);
} }
@ -2048,7 +2049,7 @@ int readHdbValue(hdbValue * v, char *data, char *error, int errlen)
getNextHdbNumber(data, number); getNextHdbNumber(data, number);
status = sscanf(number, "%d", &v->v.intValue); status = sscanf(number, "%d", &v->v.intValue);
if (status != 1) { if (status != 1) {
snprintf(error, errlen, "Failed to convert %s to integer", data); snprintf(error, errlen, "Failed to convert [%.32s] to integer", data);
return 0; return 0;
} }
break; break;
@ -2056,7 +2057,7 @@ int readHdbValue(hdbValue * v, char *data, char *error, int errlen)
getNextHdbNumber(data, number); getNextHdbNumber(data, number);
status = sscanf(number, "%lf", &v->v.doubleValue); status = sscanf(number, "%lf", &v->v.doubleValue);
if (status != 1) { if (status != 1) {
snprintf(error, errlen, "Failed to convert %s to double", data); snprintf(error, errlen, "Failed to convert [%.32s] to double", data);
return 0; return 0;
} }
break; break;
@ -2082,7 +2083,7 @@ int readHdbValue(hdbValue * v, char *data, char *error, int errlen)
} }
status = sscanf(number, "%d", &lValue); status = sscanf(number, "%d", &lValue);
if (status != 1) { if (status != 1) {
snprintf(error, errlen, "Failed to convert %s to integer", data); snprintf(error, errlen, "Failed to convert [%.32s] to integer", data);
return 0; return 0;
} }
v->v.intArray[i] = lValue; v->v.intArray[i] = lValue;
@ -2104,7 +2105,7 @@ int readHdbValue(hdbValue * v, char *data, char *error, int errlen)
} }
status = sscanf(number, "%lf", &dValue); status = sscanf(number, "%lf", &dValue);
if (status != 1) { if (status != 1) {
snprintf(error, errlen, "Failed to convert %s to double", data); snprintf(error, errlen, "Failed to convert [%.32s] to double", data);
return 0; return 0;
} }
v->v.floatArray[i] = dValue; v->v.floatArray[i] = dValue;
@ -2154,7 +2155,7 @@ int convertHdbType(char *text)
type = 0; type = 0;
while (hdbTypes[type] != NULL) { while (hdbTypes[type] != NULL) {
if (strcmp(hdbTypes[type], text) == 0) { if (strcasecmp(hdbTypes[type], text) == 0) {
break; break;
} }
type++; type++;
@ -2196,7 +2197,6 @@ static int MakeHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData,
/* /*
* convert datatype * convert datatype
*/ */
strtolower(argv[3]);
type = convertHdbType(argv[3]); type = convertHdbType(argv[3]);
if (type > HIPFLOATVARAR) { if (type > HIPFLOATVARAR) {
SCWrite(pCon, SCWrite(pCon,
@ -2210,7 +2210,7 @@ static int MakeHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData,
eError); eError);
return 0; return 0;
} else { } else {
length = atoi(argv[3]); length = atoi(argv[4]);
} }
} }
@ -2439,7 +2439,8 @@ static int UpdateHdbNode(SConnection * pCon, SicsInterp * pSics,
SCWrite(pCon, "ERROR: out of memory reading parameter", eError); SCWrite(pCon, "ERROR: out of memory reading parameter", eError);
return 0; return 0;
} }
for (i = 2; i < argc; i++) { DynStringConcat(parData, argv[2]);
for (i = 3; i < argc; i++) {
DynStringConcat(parData, " "); DynStringConcat(parData, " ");
DynStringConcat(parData, argv[i]); DynStringConcat(parData, argv[i]);
} }
@ -3310,7 +3311,7 @@ static int GetSICSHdbProperty(SConnection * pCon, SicsInterp * pSics,
} }
status = GetHdbProperty(targetNode, argv[2], buffer, 511); status = GetHdbProperty(targetNode, argv[2], buffer, 511);
if (status != 1) { if (status != 1) {
SCPrintf(pCon, eError, "ERROR: property %s not found", argv[2]); SCPrintf(pCon, eError, "ERROR: %s has no property %s", argv[1], argv[2]);
return 0; return 0;
} }
SCPrintf(pCon, eValue, "%s.%s = %s", argv[1], argv[2], buffer); SCPrintf(pCon, eValue, "%s.%s = %s", argv[1], argv[2], buffer);
@ -3331,12 +3332,12 @@ static int GetSICSHdbPropertyVal(SConnection * pCon, SicsInterp * pSics,
} }
targetNode = FindHdbNode(NULL, argv[1], pCon); targetNode = FindHdbNode(NULL, argv[1], pCon);
if (targetNode == NULL) { if (targetNode == NULL) {
SCWrite(pCon, "ERROR: node not found", eValue); SCWrite(pCon, "ERROR: node not found", eError);
return 0; return 0;
} }
status = GetHdbProperty(targetNode, argv[2], buffer, 511); status = GetHdbProperty(targetNode, argv[2], buffer, 511);
if (status != 1) { if (status != 1) {
SCWrite(pCon, "ERROR: attribute not found", eValue); SCPrintf(pCon, eError, "ERROR: %s has no property %s", argv[1], argv[2]);
return 0; return 0;
} }
SCPrintf(pCon, eValue, "%s", buffer); SCPrintf(pCon, eValue, "%s", buffer);

View File

@ -284,6 +284,10 @@ int GetHdbPath(pHdb nodeArg, char *path, size_t pathlen);
* @param internalID the internalID to be looked for * @param internalID the internalID to be looked for
*/ */
void RemoveSICSInternalCallback(void *internalID); void RemoveSICSInternalCallback(void *internalID);
/** Remove all Callbacks rooted in the node
* @param internalID the internalID to be looked for
*/
void RemoveSICSInternalCallbackFrom(pHdb node, void *internalID);
/** /**
* SICSHdbGetPar returns the value of a parameter. * SICSHdbGetPar returns the value of a parameter.
* @param obj The object for which to get a parameter. * @param obj The object for which to get a parameter.

View File

@ -17,7 +17,11 @@
#include "initializer.h" #include "initializer.h"
#include "splitter.h" #include "splitter.h"
extern int decodeSICSPriv(char *txt); /* from access.c */ typedef struct {
char *name;
char *class;
} NameClass;
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
void DefaultKill(void *data) void DefaultKill(void *data)
{ {
@ -74,6 +78,42 @@ int SaveSICSOBJ(void *data, char *name, FILE * fd)
return 1; return 1;
} }
/*---------------------------------------------------------------------------*/
static void KillSICSOBJfromNode(void *userData)
{
NameClass *nameClass = userData;
SICSOBJ *sicsobj;
sicsobj = FindCommandData(pServ->pSics, nameClass->name, nameClass->class);
if (sicsobj) {
sicsobj->objectNode = NULL; /* do not call RemoveHdbNodeFromParent in KillSICSOBJ */
sicsobj->pDes->parNode = NULL; /* do not free the node twice in KillSICSOBJ/DeleteDescriptor */
RemoveCommand(pServ->pSics, nameClass->name);
}
free(nameClass->name);
free(nameClass->class);
free(nameClass);
}
/*---------------------------------------------------------------------------*/
static hdbCallbackReturn DummyCallback(Hdb *node, void *userData,
hdbMessage *msg)
{
return hdbContinue;
}
/*---------------------------------------------------------------------------*/
void RegisterSICSOBJKillCmd(pSICSOBJ sicsobj, char *name)
{
hdbCallback *cb;
NameClass *nameClass;
nameClass = calloc(1, sizeof(*nameClass));
nameClass->name = strdup(name);
nameClass->class = strdup(sicsobj->pDes->name);
/* use only the kill function */
cb = MakeHipadabaCallback(DummyCallback, nameClass, KillSICSOBJfromNode);
assert(cb);
AppendHipadabaCallback(sicsobj->objectNode, cb);
}
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
pSICSOBJ MakeSICSOBJv(char *name, char *class, int type, int priv) pSICSOBJ MakeSICSOBJv(char *name, char *class, int type, int priv)
{ {
@ -119,8 +159,11 @@ void KillSICSOBJ(void *data)
if (self->KillPrivate != NULL && self->pPrivate != NULL) { if (self->KillPrivate != NULL && self->pPrivate != NULL) {
self->KillPrivate(self->pPrivate); self->KillPrivate(self->pPrivate);
} }
RemoveHdbNodeFromParent(self->objectNode, pServ->dummyCon); if (self->objectNode != NULL) {
RemoveHdbNodeFromParent(self->objectNode, pServ->dummyCon);
}
if (self->pDes != NULL) { if (self->pDes != NULL) {
self->objectNode = NULL; /* inhibit SICSOBJcallback from deleting twice */
DeleteDescriptor(self->pDes); /* kill descriptor including node */ DeleteDescriptor(self->pDes); /* kill descriptor including node */
} }
free(self); free(self);
@ -412,11 +455,11 @@ int InterInvokeSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData,
if (status == -1) { if (status == -1) {
status = 0; status = 0;
if (argc > 1) { if (argc > 1) {
snprintf(buffer, 131, snprintf(buffer, sizeof buffer,
"ERROR: no command or parameter found for key: %s", "ERROR: %s %s not found",
argv[1]); argv[0], argv[1]);
} else { } else {
snprintf(buffer, 131, "ERROR: no argument found"); snprintf(buffer, sizeof buffer, "ERROR: no argument found");
} }
SCWrite(pCon, buffer, eError); SCWrite(pCon, buffer, eError);
status = 0; status = 0;
@ -444,7 +487,6 @@ pSICSOBJ SetupSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData,
/* convert privilege */ /* convert privilege */
priv = decodeSICSPriv(argv[3]); priv = decodeSICSPriv(argv[3]);
/* convert datatype */ /* convert datatype */
strtolower(argv[4]);
type = convertHdbType(argv[4]); type = convertHdbType(argv[4]);
if (type > HIPFLOAT) { if (type > HIPFLOAT) {
SCWrite(pCon, SCWrite(pCon,
@ -464,6 +506,7 @@ pSICSOBJ SetupSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData,
SetDescriptorKey(pNew->pDes, "creationCommand", "0"); SetDescriptorKey(pNew->pDes, "creationCommand", "0");
} }
SetHdbProperty(pNew->objectNode, "objectName", argv[1]);
status = AddCommand(pSics, status = AddCommand(pSics,
argv[1], InterInvokeSICSOBJ, KillSICSOBJ, pNew); argv[1], InterInvokeSICSOBJ, KillSICSOBJ, pNew);
if (status != 1) { if (status != 1) {

View File

@ -31,6 +31,9 @@ void KillSICSOBJ(void *data);
void DefaultKill(void *data); void DefaultKill(void *data);
void DefaultFree(void *data); void DefaultFree(void *data);
/* register a callback for killing the command when the node is killed */
void RegisterSICSOBJKillCmd(pSICSOBJ sicsobj, char *name);
int SaveSICSOBJ(void *data, char *name, FILE * fd); int SaveSICSOBJ(void *data, char *name, FILE * fd);
/** /**

View File

@ -259,6 +259,12 @@ const char *StringDictGetNext(pStringDict self, char *pValue, int iValLen)
} else { } else {
LLDnodeDataTo(self->iList, &sVal); LLDnodeDataTo(self->iList, &sVal);
strncpy(pValue, sVal.value, iValLen); strncpy(pValue, sVal.value, iValLen);
/* strncpy is not guaranteed to be '\0' terminated */
if (iValLen > 0 && pValue[iValLen-1] != '\0') {
/* overflow */
pValue[iValLen-1] = '\0';
}
return sVal.name; return sVal.name;
} }
} else { /* start a new one */ } else { /* start a new one */
@ -270,6 +276,11 @@ const char *StringDictGetNext(pStringDict self, char *pValue, int iValLen)
self->iTraverse = 1; self->iTraverse = 1;
LLDnodeDataTo(self->iList, &sVal); LLDnodeDataTo(self->iList, &sVal);
strncpy(pValue, sVal.value, iValLen); strncpy(pValue, sVal.value, iValLen);
/* strncpy is not guaranteed to be '\0' terminated */
if (iValLen > 0 && pValue[iValLen-1] != '\0') {
/* overflow */
pValue[iValLen-1] = '\0';
}
return sVal.name; return sVal.name;
} }
} }

27
task.c
View File

@ -344,3 +344,30 @@ int TaskContinue(pTaskMan self)
self->iStop = 0; self->iStop = 0;
return 1; return 1;
} }
/*--------------------------------------------------------------------------*/
void TaskRemove(pTaskMan self, TaskFunc pTaskRun, void *pData)
{
int iRet;
pTaskHead pCurrent, pNext;
assert(self);
assert(self->iID == TASKERID);
pNext = self->pHead->pNext; /* skip dummy task */
while (pNext != NULL) {
pCurrent = pNext;
pNext = pCurrent->pNext;
if (pCurrent->pRun == pTaskRun && pCurrent->pData == pData) {
/* unlink */
if (pCurrent->pPrevious != NULL) {
pCurrent->pPrevious->pNext = pCurrent->pNext;
}
if (pCurrent->pNext != NULL) {
pCurrent->pNext->pPrevious = pCurrent->pPrevious;
}
free(pCurrent);
}
}
return;
}

6
task.h
View File

@ -113,5 +113,9 @@ int TaskSignal(pTaskMan self, int iSignal, void *pSigData);
pSigData. pSigData.
*/ */
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
void TaskRemove(pTaskMan self, TaskFunc pTaskRun, void *pData);
/*
remove the task with the given task function and the given data pointer
*/
#endif #endif