- allow scriptcontext objects to be dynamic
- enhancements in scriptcontext (error messages stored as properties)
This commit is contained in:
@ -213,7 +213,9 @@ int RemoveCommand(SicsInterp * pInterp, char *pName)
|
||||
/* found, remove it */
|
||||
/* kall KillFunction first */
|
||||
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 */
|
||||
@ -237,7 +239,6 @@ int RemoveCommand(SicsInterp * pInterp, char *pName)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#define MAXLEN 256
|
||||
#define MAXCOM 50
|
||||
extern char *stptok(char *s, char *tok, unsigned int toklen, char *brk);
|
||||
@ -1047,8 +1048,7 @@ char *FindAliases(SicsInterp * pSics, char *name)
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
void
|
||||
ForEachCommand(int (*scanFunction)
|
||||
void ForEachCommand(int (*scanFunction)
|
||||
(char *name, pDummy object, void *userData)
|
||||
, void *userData)
|
||||
{
|
||||
|
128
ascon.c
128
ascon.c
@ -14,6 +14,8 @@
|
||||
#include "ascon.i"
|
||||
#include "uselect.h"
|
||||
|
||||
static double lastClose = 0; /* time of last close operation */
|
||||
|
||||
/*
|
||||
CreateSocketAdress stolen from Tcl. Thanks to John Ousterhout
|
||||
*/
|
||||
@ -63,7 +65,7 @@ double DoubleTime(void)
|
||||
void AsconError(Ascon *a, char *msg, int errorno)
|
||||
{
|
||||
static char *stateText[]={
|
||||
"state 0", "kill", "state 2", "notConnected",
|
||||
"state 0", "state 1", "state 2", "notConnected",
|
||||
"connect", "start connect", "connect finished", "connect failed",
|
||||
"write", "start write", "write finished", "write failed",
|
||||
"read", "start read", "read finished", "read failed",
|
||||
@ -76,13 +78,19 @@ void AsconError(Ascon * a, char *msg, int errorno)
|
||||
} else {
|
||||
state = stateText[a->state];
|
||||
}
|
||||
if (errorno != 0) {
|
||||
a->errList =
|
||||
ErrPutMsg(a->errList, "ASCERR: %s %s (during %s)", msg,
|
||||
strerror(errorno), state);
|
||||
DynStringCopy(a->errmsg, "ASCERR: ");
|
||||
if (errorno == 0) {
|
||||
DynStringConcat(a->errmsg, msg);
|
||||
DynStringConcat(a->errmsg, " (");
|
||||
DynStringConcat(a->errmsg, state);
|
||||
DynStringConcat(a->errmsg, " state)");
|
||||
} else {
|
||||
a->errList =
|
||||
ErrPutMsg(a->errList, "ASCERR: %s (during %s)", msg, state);
|
||||
DynStringConcat(a->errmsg, strerror(errorno));
|
||||
DynStringConcat(a->errmsg, " (");
|
||||
DynStringConcat(a->errmsg, state);
|
||||
DynStringConcat(a->errmsg, " state, ");
|
||||
DynStringConcat(a->errmsg, msg);
|
||||
DynStringConcat(a->errmsg, ")");
|
||||
}
|
||||
a->state |= AsconFailed;
|
||||
}
|
||||
@ -97,10 +105,22 @@ static void AsconConnect(Ascon * a)
|
||||
int port;
|
||||
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) {
|
||||
a->fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (a->fd < 0) {
|
||||
AsconError(a, "socket failed:", errno);
|
||||
AsconError(a, "ASC1", errno);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -119,7 +139,6 @@ static void AsconConnect(Ascon * a)
|
||||
AsconError(a, "bad host specification", 0);
|
||||
return;
|
||||
}
|
||||
/* should we insert the workaround for lantronix server ? see network.c */
|
||||
oldopts = fcntl(a->fd, F_GETFL, 0);
|
||||
fcntl(a->fd, F_SETFL, oldopts | O_NONBLOCK);
|
||||
ret =
|
||||
@ -132,7 +151,7 @@ static void AsconConnect(Ascon * a)
|
||||
a->state = AsconConnecting;
|
||||
break;
|
||||
default:
|
||||
AsconError(a, "connect failed:", errno);
|
||||
AsconError(a, "ASC2", errno);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -144,7 +163,6 @@ int AsconStdInit(Ascon * a, SConnection * con, int argc, char *argv[])
|
||||
{
|
||||
a->fd = -1;
|
||||
a->state = AsconConnectStart;
|
||||
a->reconnectInterval = 10;
|
||||
a->hostport = strdup(argv[1]);
|
||||
if (argc > 2) {
|
||||
a->sendTerminator = strdup(argv[2]);
|
||||
@ -156,6 +174,10 @@ int AsconStdInit(Ascon * a, SConnection * con, int argc, char *argv[])
|
||||
} else {
|
||||
a->timeout = 2.0; /* sec */
|
||||
}
|
||||
a->replyTerminator == NULL;
|
||||
if (argc > 4 && argv[4][0] != '\0') {
|
||||
a->replyTerminator = strdup(argv[4]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -172,9 +194,11 @@ int AsconReadGarbage(int fd)
|
||||
FD_SET(fd, &rmask);
|
||||
ret = uselect(fd + 1, &rmask, NULL, NULL, &tmo);
|
||||
if (ret > 0) {
|
||||
l = recv(fd, garbage, sizeof garbage, 0);
|
||||
l = recv(fd, garbage, sizeof garbage - 1, 0);
|
||||
if (l > 0) {
|
||||
/* swallow */
|
||||
garbage[l] = '\0';
|
||||
printf("(((%s)))\n", garbage);
|
||||
result += l;
|
||||
} else if (l == 0) {
|
||||
errno = ECONNRESET;
|
||||
@ -307,7 +331,7 @@ int AsconStdHandler(Ascon * a)
|
||||
} else if (ret > 0) {
|
||||
a->state = AsconConnectDone; /* success */
|
||||
} else if (ret < 0) {
|
||||
AsconError(a, "AsconConnectSuccess failed:", errno);
|
||||
AsconError(a, "ASC3", errno);
|
||||
}
|
||||
break;
|
||||
case AsconWriteStart:
|
||||
@ -320,13 +344,22 @@ int AsconStdHandler(Ascon * a)
|
||||
}
|
||||
break;
|
||||
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);
|
||||
l = GetDynStringLength(a->wrBuffer) - a->wrPos;
|
||||
ret = AsconWriteChars(a->fd, GetCharArray(a->wrBuffer) + a->wrPos, l);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
AsconError(a, "send failed:", errno);
|
||||
}
|
||||
AsconError(a, "ASC4", errno);
|
||||
/*
|
||||
* Ooops: which state shall we go to after a write fail?
|
||||
* This seems to retry.
|
||||
@ -348,22 +381,32 @@ int AsconStdHandler(Ascon * a)
|
||||
while (ret > 0) {
|
||||
a->start = DoubleTime();
|
||||
|
||||
if (a->replyTerminator != NULL) {
|
||||
if (strchr(a->replyTerminator, chr) != NULL) {
|
||||
DynStringConcatChar(a->rdBuffer, chr);
|
||||
DynStringConcatChar(a->rdBuffer, '\0');
|
||||
a->state = AsconReadDone;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (chr == '\n') {
|
||||
if (a->readState) {
|
||||
if (a->readState) { /* last char was CR */
|
||||
/* swallow LF after CR */
|
||||
DynStringClear(a->rdBuffer);
|
||||
a->readState = 0;
|
||||
chr = 0;
|
||||
} else {
|
||||
DynStringConcatChar(a->rdBuffer, '\0');
|
||||
a->state = AsconReadDone;
|
||||
break;
|
||||
}
|
||||
} else if (chr == '\r') {
|
||||
a->readState = 1;
|
||||
a->readState = 1; /* set 'last char was CR' */
|
||||
DynStringConcatChar(a->rdBuffer, '\0');
|
||||
a->state = AsconReadDone;
|
||||
break;
|
||||
} else {
|
||||
}
|
||||
}
|
||||
if (chr != 0) {
|
||||
if (DynStringConcatChar(a->rdBuffer, chr) == 0) {
|
||||
AsconError(a, "DynStringConcatChar failed:", ENOMEM);
|
||||
break;
|
||||
@ -375,7 +418,7 @@ int AsconStdHandler(Ascon * a)
|
||||
if (ret < 0) {
|
||||
/* EINTR means we shall retry */
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
AsconError(a, "AsconReadChar failed:", errno);
|
||||
AsconError(a, "ASC5", errno);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -384,27 +427,23 @@ int AsconStdHandler(Ascon * a)
|
||||
} else {
|
||||
if (a->timeout > 0) {
|
||||
if (DoubleTime() - a->start > a->timeout) {
|
||||
AsconError(a, "read timeout", 0);
|
||||
AsconError(a, "no response", 0);
|
||||
a->state = AsconTimeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* define type AsconProtocolList and functions AsconProtocolAdd etc. */
|
||||
#define MC_NAME(T) AsconProtocol##T
|
||||
#include "mclist.c"
|
||||
static AsconProtocol *protocols = NULL;
|
||||
|
||||
static AsconProtocolList protocols = { 0 };
|
||||
|
||||
void AsconInsertProtocol(AsconProtocol * protocol)
|
||||
{
|
||||
AsconProtocolAdd(&protocols, protocol);
|
||||
void AsconInsertProtocol(AsconProtocol *protocol) {
|
||||
protocol->next = protocols;
|
||||
protocols = protocol;
|
||||
}
|
||||
|
||||
AsconHandler AsconSetHandler(Ascon *a, SConnection *con,
|
||||
@ -420,7 +459,7 @@ AsconHandler AsconSetHandler(Ascon * a, SConnection * con,
|
||||
AsconStdInit(a, con, argc, argv);
|
||||
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 (p->init(a, con, argc, argv)) {
|
||||
return p->handler;
|
||||
@ -460,10 +499,8 @@ Ascon *AsconMake(SConnection * con, int argc, char *argv[])
|
||||
}
|
||||
a->rdBuffer = CreateDynString(60, 63);
|
||||
a->wrBuffer = CreateDynString(60, 63);
|
||||
a->errList = NULL;
|
||||
a->errmsg = CreateDynString(60, 63);
|
||||
a->responseValid = 0;
|
||||
a->reconnectInterval = 10;
|
||||
a->lastReconnect = 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
@ -471,15 +508,20 @@ void AsconKill(Ascon * a)
|
||||
{
|
||||
if (a->fd > 0) {
|
||||
close(a->fd);
|
||||
lastClose = DoubleTime();
|
||||
}
|
||||
DeleteDynString(a->rdBuffer);
|
||||
DeleteDynString(a->wrBuffer);
|
||||
DeleteDynString(a->errmsg);
|
||||
if (a->hostport) {
|
||||
free(a->hostport);
|
||||
}
|
||||
if(a->sendTerminator){
|
||||
free(a->sendTerminator);
|
||||
}
|
||||
if(a->replyTerminator){
|
||||
free(a->replyTerminator);
|
||||
}
|
||||
if (a->private != NULL && a->killPrivate != NULL) {
|
||||
a->killPrivate(a->private);
|
||||
}
|
||||
@ -528,17 +570,15 @@ AsconStatus AsconTask(Ascon * a)
|
||||
case AsconStart:
|
||||
return AsconPending;
|
||||
case AsconFailed:
|
||||
if (a->state != AsconTimeout) {
|
||||
now = DoubleTime();
|
||||
if (now > a->lastReconnect + a->reconnectInterval) {
|
||||
a->lastReconnect = now;
|
||||
if (a->state == AsconTimeout) {
|
||||
a->state = AsconIdle;
|
||||
} else {
|
||||
close(a->fd);
|
||||
/* allow the system to cleanup the socket, otherwise a reconnect will fail */
|
||||
sleep(1);
|
||||
lastClose = DoubleTime();
|
||||
a->fd = -1;
|
||||
a->state = AsconConnectStart;
|
||||
}
|
||||
}
|
||||
|
||||
return AsconFailure;
|
||||
case AsconFinished:
|
||||
if (a->state < AsconConnectFailed) {
|
||||
@ -580,7 +620,7 @@ char *AsconRead(Ascon * a)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ErrMsg *AsconGetErrList(Ascon * a)
|
||||
char *AsconGetError(Ascon *a)
|
||||
{
|
||||
return a->errList;
|
||||
return GetCharArray(a->errmsg);
|
||||
}
|
||||
|
15
ascon.h
15
ascon.h
@ -2,7 +2,6 @@
|
||||
#define ASCON_H
|
||||
|
||||
#include "sics.h"
|
||||
#include "errormsg.h"
|
||||
|
||||
/** \file
|
||||
* \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
|
||||
* NULL when the command has not completed and the response is not yet finished
|
||||
* "" when the command has completed, but no response was expected.
|
||||
* The result is only valid until the next call to other AsconXxx functions
|
||||
* and has to be duplicated if needed later.
|
||||
* 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.
|
||||
*/
|
||||
char *AsconRead(Ascon * a);
|
||||
|
||||
/** \brief get the connections error list
|
||||
* \return the error list
|
||||
/** \brief get the last error message
|
||||
* \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
|
||||
* \param argc the number of args
|
||||
@ -78,7 +79,7 @@ ErrMsg *AsconGetErrList(Ascon * a);
|
||||
*/
|
||||
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
|
||||
*/
|
||||
double DoubleTime(void);
|
||||
|
14
ascon.i
14
ascon.i
@ -12,7 +12,7 @@
|
||||
* For the implementation of a custom protocol, you have to implement
|
||||
* the handler function and the init function, declare the protocol
|
||||
* 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
|
||||
*
|
||||
* The functions with fd as the first argument are utility functions with
|
||||
@ -64,8 +64,9 @@ struct Ascon {
|
||||
int wrPos; /**< write buffer position */
|
||||
double timeout; /**< read timeout (sec) */
|
||||
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 */
|
||||
ErrMsg *errList; /**< error message list */
|
||||
pDynString errmsg; /**< error message */
|
||||
double start; /**< unix time when read was started */
|
||||
void *private; /**< private data of protocol */
|
||||
void (*killPrivate)(void *); /** < kill function for private */
|
||||
@ -73,7 +74,6 @@ struct Ascon {
|
||||
int responseValid; /**< a valid response is ready */
|
||||
AsconHandler handler; /**< handler function */
|
||||
double reconnectInterval; /**< reconnect interval */
|
||||
double lastReconnect; /**< last connect try */
|
||||
};
|
||||
|
||||
#define ASCON_SELECT_ERROR -1
|
||||
@ -92,7 +92,13 @@ int AsconStdHandler(Ascon *a);
|
||||
/** \brief initialize a standard connection
|
||||
* \param a the connection
|
||||
* \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
|
||||
*/
|
||||
|
22
commandlog.c
22
commandlog.c
@ -89,7 +89,6 @@ void WriteToCommandLogId(char *prompt, int id, char *text)
|
||||
return;
|
||||
strncpy(pCopy, text, l);
|
||||
pCopy[l] = '\0';
|
||||
|
||||
if (prompt == cmdPrompt && iCompact) {
|
||||
pPtr = strstr(pCopy, "fulltransact ");
|
||||
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 */
|
||||
if (!pTail) {
|
||||
pTail = createCircular(MAXTAIL, free);
|
||||
}
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
doStamp = 0;
|
||||
doStampId = 0;
|
||||
|
||||
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) {
|
||||
prompt = "";
|
||||
} else {
|
||||
@ -125,7 +137,7 @@ void WriteToCommandLogId(char *prompt, int id, char *text)
|
||||
snprintf(buffer, sizeof buffer, "sock %d>%s ", id, prompt);
|
||||
}
|
||||
prompt = buffer;
|
||||
} else {
|
||||
} else if (iCompact > 1) {
|
||||
if (id != lastId) {
|
||||
lastId = id;
|
||||
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) {
|
||||
doStamp = 1;
|
||||
doStampId = 1;
|
||||
|
39
devexec.c
39
devexec.c
@ -788,6 +788,40 @@ int StopExe(pExeList self, char *name)
|
||||
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)
|
||||
{
|
||||
@ -795,7 +829,6 @@ int StopExeWait(pExeList self)
|
||||
Wait4Success(self);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int PauseExecution(pExeList self)
|
||||
{
|
||||
@ -1006,7 +1039,6 @@ int SicsIdle(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
Usage:
|
||||
Success
|
||||
*/
|
||||
|
||||
int Success(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
@ -1020,6 +1052,8 @@ int Success(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
if (SCGetInterrupt(pCon) == eAbortOperation) {
|
||||
SCSetInterrupt(pCon, eContinue);
|
||||
iRet = 0;
|
||||
} else {
|
||||
iRet = 1;
|
||||
}
|
||||
} else if (iRet == DEVDONE) {
|
||||
SCWrite(pCon, "All done", eValue);
|
||||
@ -1031,7 +1065,6 @@ int Success(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
SetStatus(eEager);
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
int PauseAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
|
16
devexec.h
16
devexec.h
@ -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,
|
||||
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);
|
||||
|
||||
|
||||
#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
|
||||
to complete.
|
||||
*/
|
||||
|
||||
int StopByData(pExeList self, void *data);
|
||||
/* stop the entry with the given data from execution */
|
||||
/*------------------------------------------------------------------------*/
|
||||
void ClearExecutor(pExeList self);
|
||||
/*
|
||||
@ -115,7 +118,7 @@ int PauseExecution(pExeList self);
|
||||
int ContinueExecution(pExeList self);
|
||||
|
||||
|
||||
#line 259 "devexec.w"
|
||||
#line 261 "devexec.w"
|
||||
|
||||
/*-------------------------- Commands ------------------------------------*/
|
||||
int DevexecAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
@ -157,16 +160,15 @@ int ContinueAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
|
||||
/*--------------------------- Locking ---------------------------------*/
|
||||
|
||||
#line 183 "devexec.w"
|
||||
#line 185 "devexec.w"
|
||||
|
||||
void LockDeviceExecutor(pExeList self);
|
||||
void UnlockDeviceExecutor(pExeList self);
|
||||
|
||||
|
||||
#line 299 "devexec.w"
|
||||
#line 301 "devexec.w"
|
||||
|
||||
/* -------------------------- Executor management -------------------------*/
|
||||
|
||||
pExeList GetExecutor(void);
|
||||
void SetExecutor(pExeList pExe);
|
||||
/*----------------------- Logging -----------------------------------------*/
|
||||
|
12
devexec.tex
12
devexec.tex
@ -52,7 +52,7 @@ $\langle$devreg {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ char *name, float fNew);@\\
|
||||
\mbox{}\verb@ int StartCounter(pExeList self, SicsInterp *pSics, SConnection *pCon,@\\
|
||||
\mbox{}\verb@ char *name); @\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\mbox{}\verb@@$\Diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
@ -115,7 +115,7 @@ $\langle$devcheck {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ int DevExecTask(void *pEL);@\\
|
||||
\mbox{}\verb@ void DevExecSignal(void *pEL, int iSignal, void *pSigData);@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\mbox{}\verb@@$\Diamond$
|
||||
\end{list}
|
||||
\vspace{-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@ to complete.@\\
|
||||
\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@ void ClearExecutor(pExeList self);@\\
|
||||
\mbox{}\verb@ /*@\\
|
||||
@ -184,7 +186,7 @@ $\langle$devstop {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ int PauseExecution(pExeList self);@\\
|
||||
\mbox{}\verb@ int ContinueExecution(pExeList self);@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\mbox{}\verb@@$\Diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
@ -226,7 +228,7 @@ $\langle$devlock {\footnotesize ?}$\rangle\equiv$
|
||||
\mbox{}\verb@ void LockDeviceExecutor(pExeList self);@\\
|
||||
\mbox{}\verb@ void UnlockDeviceExecutor(pExeList self);@\\
|
||||
\mbox{}\verb@@\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\mbox{}\verb@@$\Diamond$
|
||||
\end{list}
|
||||
\vspace{-1ex}
|
||||
\footnotesize\addtolength{\baselineskip}{-1ex}
|
||||
@ -358,7 +360,7 @@ to the global SICS device executor.
|
||||
\mbox{}\verb@/*----------------------- Logging -----------------------------------------*/@\\
|
||||
\mbox{}\verb@ void DevexecLog(char *op, char *device); @\\
|
||||
\mbox{}\verb@#endif @\\
|
||||
\mbox{}\verb@@$\diamond$
|
||||
\mbox{}\verb@@$\Diamond$
|
||||
\end{list}
|
||||
\vspace{-2ex}
|
||||
\end{minipage}\\[4ex]
|
||||
|
@ -144,6 +144,8 @@ This is done via the following interface.
|
||||
StopExeWait will stop all running things and wait for the stop
|
||||
to complete.
|
||||
*/
|
||||
int StopByData(pExeList self, void *data);
|
||||
/* stop the entry with the given data from execution */
|
||||
/*------------------------------------------------------------------------*/
|
||||
void ClearExecutor(pExeList self);
|
||||
/*
|
||||
|
47
devser.c
47
devser.c
@ -24,14 +24,14 @@ struct DevSer {
|
||||
DevAction *current;
|
||||
int killCurrent;
|
||||
DevAction *actions; /* the action queue */
|
||||
DevAction *toKill; /* list of actions to be killed */
|
||||
SchedHeader *headers;
|
||||
ErrMsg *errmsg;
|
||||
int steps;
|
||||
int stopTask;
|
||||
};
|
||||
|
||||
static char *devPrio[NumberOfPRIO] = {
|
||||
"null", "slow", "read", "progress", "write", "halt"
|
||||
"null", "slow", "read", "progress", "write", "halt", "start"
|
||||
};
|
||||
|
||||
char *DevPrio2Text(DevPrio prio)
|
||||
@ -100,6 +100,9 @@ DevAction *DevNextAction(DevSer * devser)
|
||||
header->timeDue = (floor(now / header->interval) + 1)
|
||||
* 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) {
|
||||
@ -123,13 +126,18 @@ int DevQueueTask(void *ds)
|
||||
AsconStatus status;
|
||||
DevAction *action;
|
||||
char *sendData;
|
||||
char *replyData;
|
||||
char *replyData = NULL;
|
||||
|
||||
if (devser->steps == 0)
|
||||
return 1;
|
||||
if (devser->stopTask) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* deferred deallocation of removed actions */
|
||||
DevFreeActionList(devser->toKill);
|
||||
devser->toKill = NULL;
|
||||
|
||||
action = devser->current;
|
||||
if (action == NULL) {
|
||||
action = DevNextAction(devser);
|
||||
@ -138,19 +146,16 @@ int DevQueueTask(void *ds)
|
||||
while (action != NULL) {
|
||||
status = AsconTask(devser->asyncConn);
|
||||
if (status == AsconFailure) {
|
||||
devser->errmsg = AsconGetErrList(devser->asyncConn);
|
||||
} else if (status != AsconReady) {
|
||||
replyData = AsconGetError(devser->asyncConn);
|
||||
} else if (status == AsconReady) {
|
||||
replyData = AsconRead(devser->asyncConn);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
if (devser->steps > 0) { /* debugging mode */
|
||||
devser->steps--;
|
||||
}
|
||||
if (status == AsconFailure) {
|
||||
replyData = devser->errmsg->text;
|
||||
} else {
|
||||
replyData = AsconRead(devser->asyncConn);
|
||||
}
|
||||
sendData = action->hdl(action->data, replyData);
|
||||
sendData = action->hdl(action->data, replyData, (status == AsconFailure));
|
||||
if (sendData != NULL) {
|
||||
AsconWrite(devser->asyncConn, sendData, 0);
|
||||
return 1;
|
||||
@ -184,6 +189,7 @@ DevSer *DevMake(SConnection * con, int argc, char *argv[])
|
||||
devser->actions = NULL;
|
||||
devser->headers = NULL;
|
||||
devser->stopTask = 0;
|
||||
devser->toKill = NULL;
|
||||
devser->steps = -1; /* no debugging by default */
|
||||
TaskRegister(pServ->pTasker, DevQueueTask, NULL, DevKillTask, devser, 0);
|
||||
return devser;
|
||||
@ -216,6 +222,7 @@ void DevKill(DevSer * devser)
|
||||
AsconKill(devser->asyncConn);
|
||||
}
|
||||
DevFreeActionList(devser->actions);
|
||||
DevFreeActionList(devser->toKill);
|
||||
h = devser->headers;
|
||||
while (h != NULL) {
|
||||
victim = h;
|
||||
@ -223,6 +230,11 @@ void DevKill(DevSer * devser)
|
||||
DevFreeActionList(victim->actions);
|
||||
free(victim);
|
||||
}
|
||||
if (devser->killCurrent) {
|
||||
if (devser->current->kill != NULL) devser->current->kill(devser->current);
|
||||
devser->killCurrent = 0;
|
||||
free(devser->current);
|
||||
}
|
||||
if (devser->stopTask) {
|
||||
free(devser);
|
||||
} else {
|
||||
@ -286,9 +298,9 @@ int DevUnschedule(DevSer * devser, void *actionData,
|
||||
cnt++;
|
||||
/* remove from list */
|
||||
*ptr2Last = action->next;
|
||||
if (action->kill != NULL)
|
||||
action->kill(action->data);
|
||||
free(action);
|
||||
/* add to kill list */
|
||||
action->next = devser->toKill;
|
||||
devser->toKill = action;
|
||||
} else {
|
||||
ptr2Last = &action->next;
|
||||
}
|
||||
@ -364,8 +376,9 @@ int DevRemoveAction(DevSer * devser, void *actionData)
|
||||
int cnt = 0;
|
||||
|
||||
|
||||
/* Remove current action, if matched. If a reply is pending, the next action will
|
||||
get the reply. But as in the inital state no reply is expected, this should not harm. */
|
||||
/* Remove current action, if matched. If a reply is pending, the next
|
||||
action will get the reply. But as in the inital state no reply is
|
||||
expected, this should not harm. */
|
||||
action = devser->current;
|
||||
if (action != NULL && actionData == action->data) {
|
||||
if (devser->killCurrent) {
|
||||
@ -378,7 +391,7 @@ int DevRemoveAction(DevSer * devser, void *actionData)
|
||||
}
|
||||
/* remove from queue */
|
||||
ptr2Last = &devser->actions;
|
||||
for (action = devser->actions; action != NULL; action = action->next) {
|
||||
for (action = devser->actions; action != NULL; action = *ptr2Last) {
|
||||
if (actionData == action->data) {
|
||||
cnt++;
|
||||
/* remove from list */
|
||||
|
14
devser.h
14
devser.h
@ -10,10 +10,12 @@ typedef struct DevSer DevSer;
|
||||
/** \brief The action handler to be called
|
||||
* \param actionData the data stored with the action
|
||||
* \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
|
||||
*/
|
||||
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
|
||||
* \param callData the callers data
|
||||
@ -29,10 +31,12 @@ typedef void DevKillActionData(void *actionData);
|
||||
|
||||
/** \brief possible priorities.
|
||||
* 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 {
|
||||
NullPRIO, SlowPRIO, ReadPRIO, ProgressPRIO, WritePRIO, HaltPRIO,
|
||||
NumberOfPRIO
|
||||
StartPRIO, NumberOfPRIO
|
||||
} DevPrio;
|
||||
|
||||
/** \brief Make a new device serializer and async connection.
|
||||
@ -100,7 +104,7 @@ int DevSchedule(DevSer * devser, void *actionData,
|
||||
|
||||
/** \brief Unschedule matching actions
|
||||
* \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 matchFunc the match function (callData does not need to have the same type as actionData)
|
||||
* \return the number of unscheduled actions
|
||||
@ -114,6 +118,7 @@ int DevUnschedule(DevSer * devser, void *actionData,
|
||||
*/
|
||||
int DevRemoveAction(DevSer * devser, void *actionData);
|
||||
|
||||
|
||||
/** \brief Convert integer priority to text
|
||||
* \param prio
|
||||
* \return text
|
||||
@ -126,5 +131,4 @@ char *DevPrio2Text(DevPrio prio);
|
||||
*/
|
||||
DevPrio DevText2Prio(char *text);
|
||||
|
||||
|
||||
#endif
|
||||
|
21
errormsg.c
21
errormsg.c
@ -26,7 +26,7 @@ int ErrEqual(char *str1, char *str2)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ErrMsg *ErrPutMsg(ErrMsg * dump, char *fmt, ...)
|
||||
void ErrPutMsg(ErrList *list, char *fmt, ...)
|
||||
{
|
||||
ErrMsg *m = NULL;
|
||||
ErrMsg **last = NULL;
|
||||
@ -34,6 +34,7 @@ ErrMsg *ErrPutMsg(ErrMsg * dump, char *fmt, ...)
|
||||
char buf[256];
|
||||
char *text = NULL;
|
||||
int l;
|
||||
static long id = 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
l = vsnprintf(buf, sizeof buf, fmt, ap);
|
||||
@ -43,12 +44,13 @@ ErrMsg *ErrPutMsg(ErrMsg * dump, char *fmt, ...)
|
||||
} else {
|
||||
/* assuming we have a C99 conforming snprintf and need a larger buffer */
|
||||
text = calloc(l, 1);
|
||||
if (!text) return;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(text, l, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
last = &dump;
|
||||
for (m = dump; m != NULL; m = m->next) {
|
||||
last = &list->current;
|
||||
for (m = list->current; m != NULL; m = m->next) {
|
||||
if (ErrEqual(text, m->text)) {
|
||||
*last = m->next; /* remove found item from list */
|
||||
break;
|
||||
@ -61,12 +63,21 @@ ErrMsg *ErrPutMsg(ErrMsg * dump, char *fmt, ...)
|
||||
m = calloc(1, sizeof(*m));
|
||||
m->text = text;
|
||||
m->cnt = 1;
|
||||
m->dirty = 0;
|
||||
id++;
|
||||
m->id = id;
|
||||
} else {
|
||||
if (text != buf)
|
||||
free(text);
|
||||
m->cnt++;
|
||||
}
|
||||
m->next = dump;
|
||||
m->next = list->current;
|
||||
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;
|
||||
}
|
||||
|
20
errormsg.h
20
errormsg.h
@ -11,10 +11,17 @@
|
||||
typedef struct ErrMsg {
|
||||
struct ErrMsg *next;
|
||||
char *text; /**< the message text */
|
||||
int cnt; /**< count */
|
||||
long cnt; /**< count */
|
||||
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;
|
||||
|
||||
typedef struct {
|
||||
ErrMsg *current;
|
||||
} ErrList;
|
||||
|
||||
/** \brief Put a formatted message to the error message list
|
||||
*
|
||||
* The error message list contains only one entry for all messages
|
||||
@ -23,10 +30,17 @@ typedef struct ErrMsg {
|
||||
* when comparing messages.
|
||||
* 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
|
||||
* \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
|
||||
|
@ -86,6 +86,7 @@ void DeleteCallbackChain(pHdb node)
|
||||
InvokeCallbackChain(node, &killNodeMsg);
|
||||
|
||||
current = node->callBackChain;
|
||||
node->callBackChain = NULL;
|
||||
while (current != NULL) {
|
||||
if (current->killFunc != NULL) {
|
||||
current->killFunc(current->userData);
|
||||
|
25
macro.c
25
macro.c
@ -982,14 +982,6 @@ int TclPublish(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
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 */
|
||||
iUser = decodeSICSPriv(argv[2]);
|
||||
if (iUser < 0) {
|
||||
@ -1002,9 +994,26 @@ int TclPublish(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
/* check if the macro already exists */
|
||||
pNew = FindCommandData(pSics, argv[1], "Macro");
|
||||
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;
|
||||
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 ! */
|
||||
pNew = CreatePublish(argv[1], iUser);
|
||||
if (!pNew) {
|
||||
|
2
make_gen
2
make_gen
@ -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 \
|
||||
mcstashm.o initializer.o remob.o tclmotdriv.o protocol.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 \
|
||||
moregress.o multicounter.o regresscter.o histregress.o \
|
||||
sicshdbadapter.o polldriv.o sicspoll.o statemon.o hmslave.o \
|
||||
|
25
motor.c
25
motor.c
@ -128,28 +128,25 @@ static int MotorCheckBoundaryImpl(pMotor self, float fVal, float *fNew,
|
||||
{
|
||||
float fHard;
|
||||
float fZero;
|
||||
char pBueffel[512];
|
||||
float fLim;
|
||||
|
||||
assert(self);
|
||||
|
||||
/* check for fixed */
|
||||
if (ObVal(self->ParArray, FIX) >= 0) {
|
||||
sprintf(pBueffel, "Motor %s is Fixed", self->name);
|
||||
strncpy(pError, pBueffel, iErrLen);
|
||||
snprintf(pError, iErrLen, "Motor %s is Fixed", self->name);
|
||||
return 0; /* is this an error? */
|
||||
}
|
||||
|
||||
/* check against software boundaries */
|
||||
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);
|
||||
strncpy(pError, pBueffel, iErrLen);
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
strncpy(pError, pBueffel, iErrLen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -163,15 +160,17 @@ static int MotorCheckBoundaryImpl(pMotor self, float fVal, float *fNew,
|
||||
|
||||
/* check for hardware limits */
|
||||
if (fHard > self->pDriver->fUpper) {
|
||||
sprintf(pBueffel, "%f violates upper hardware limit %f on %s",
|
||||
fVal, self->pDriver->fUpper, self->name);
|
||||
strncpy(pError, pBueffel, iErrLen);
|
||||
fLim = self->pDriver->fUpper * ObVal(self->ParArray,SIGN) + fZero;
|
||||
snprintf(pError, iErrLen,
|
||||
"%g violates upper hardware limit %g (%g) on %s",
|
||||
fVal, fLim, self->pDriver->fUpper, self->name);
|
||||
return 0;
|
||||
}
|
||||
if (fHard < self->pDriver->fLower) {
|
||||
sprintf(pBueffel, "%f violates lower hardware limit %f on %s",
|
||||
fVal, self->pDriver->fLower, self->name);
|
||||
strncpy(pError, pBueffel, iErrLen);
|
||||
fLim = self->pDriver->fLower * ObVal(self->ParArray,SIGN) + fZero;
|
||||
snprintf(pError, iErrLen,
|
||||
"%g violates lower hardware limit %g (%g) on %s",
|
||||
fVal, fLim, self->pDriver->fLower, self->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
51
network.c
51
network.c
@ -51,6 +51,8 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include "sics.h"
|
||||
#include "commandlog.h"
|
||||
#include "uselect.h"
|
||||
|
||||
#define PORT 1
|
||||
@ -65,11 +67,6 @@ struct timeval lastclose = { -1, 0 };
|
||||
/*-----------------------------------------------------------------------
|
||||
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)
|
||||
{
|
||||
/*
|
||||
@ -674,8 +671,44 @@ int NETReadTillTerm(mkChannel * self, long timeout,
|
||||
status = NETAvailable(self, timeout - dif);
|
||||
};
|
||||
};
|
||||
assert(bufPtr > 0);
|
||||
return bufPtr;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
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 iRet;
|
||||
int iRet = 0;
|
||||
int sock;
|
||||
int oldopts;
|
||||
|
||||
@ -709,7 +742,9 @@ int NETReconnectWithFlags(mkChannel * self, int flags)
|
||||
* Get the flags and close the old socket
|
||||
*/
|
||||
oldopts = fcntl(self->sockid, F_GETFL, 0);
|
||||
if (self->sockid != 0) {
|
||||
close(self->sockid);
|
||||
}
|
||||
/* Reopen and try to get it on the olf fd */
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (self->sockid != sock) {
|
||||
|
@ -63,7 +63,7 @@ mkChannel *NETConnectWithFlags(char *name, int port, int flags);
|
||||
if (flags & 1): do not block on connect (use NETConnectFinished
|
||||
to check success)
|
||||
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);
|
||||
@ -91,8 +91,8 @@ int NETReconnectWithFlags(mkChannel * self, int flags);
|
||||
/* *********************** DATA TRANSFER ******************************** */
|
||||
|
||||
int NETWrite(mkChannel * self, char *buffer, long lLen);
|
||||
/* writes data to socket self, returns True if success,
|
||||
false otherwise.
|
||||
/* writes data to socket self, returns 1 if success,
|
||||
0 otherwise.
|
||||
*/
|
||||
|
||||
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
|
||||
or timeout.
|
||||
*/
|
||||
int NETReadRemob(mkChannel *self, long timeout, long timeout2,
|
||||
char term, char *pBuffer, int iBufLen);
|
||||
/* special version for remob */
|
||||
/* ********************* KILLING FIELD ******************************** */
|
||||
int NETClosePort(mkChannel * self);
|
||||
/* closes a port, do not forget to free the channel data-
|
||||
|
@ -448,7 +448,7 @@ int UserWait(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
if (i < 1) {
|
||||
sprintf(pBueffel, "Expected numeric argument to %s, got %s",
|
||||
argv[0], argv[1]);
|
||||
SCWrite(pCon, pBueffel, eInError);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
5
ofac.c
5
ofac.c
@ -236,6 +236,7 @@ static void InitIniCommands(SicsInterp * pInter, pTaskMan pTask)
|
||||
AddCommand(pInter, "SICSStatus", SICSStatus, NULL, NULL);
|
||||
AddCommand(pInter, "sicstime", SICSTime, NULL, NULL);
|
||||
AddCommand(pInter, "sicsdescriptor", SICSDescriptor, NULL, NULL);
|
||||
AddCommand(pInter, "silent", SICSSilent, NULL, NULL);
|
||||
AddCommand(pInter, "SetStatus", SetSICSStatus, NULL, NULL);
|
||||
AddCommand(pInter, "db", SICSDebug, NULL, NULL);
|
||||
AddCommand(pInter, "EVFactory", EVControlFactory, NULL, NULL);
|
||||
@ -439,7 +440,9 @@ void InitGeneral(void)
|
||||
INIT(InitializerInit);
|
||||
INIT(SaveHdbInit); /* must be after InitializerInit */
|
||||
INIT(SctInit);
|
||||
INIT(SctDriveInit);
|
||||
INIT(SctDriveAdapterInit);
|
||||
INIT(SctDriveObjInit);
|
||||
INIT(SctDriveAdapterInit);
|
||||
INIT(LogReaderInit);
|
||||
INIT(LogSetupInit);
|
||||
INIT(StatusFileInit);
|
||||
|
42
script.c
42
script.c
@ -485,7 +485,6 @@ int SicsPrompt(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
/*----------------------- get object descriptor name -------------------------------
|
||||
get the name of the object descriptor
|
||||
*/
|
||||
|
||||
int SICSDescriptor(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
@ -517,3 +516,44 @@ int SICSDescriptor(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
SCWrite(pCon, "notfound", eValue);
|
||||
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;
|
||||
}
|
||||
|
3
script.h
3
script.h
@ -48,4 +48,7 @@ int SicsPrompt(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
/*----------------------------------------------------------------------*/
|
||||
int SICSDescriptor(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
/*----------------------------------------------------------------------*/
|
||||
int SICSSilent(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
#endif
|
||||
|
176
scriptcontext.c
176
scriptcontext.c
@ -47,7 +47,7 @@ typedef struct SctData {
|
||||
} SctData;
|
||||
|
||||
static ScriptContext *sct = NULL;
|
||||
static SConnection *currentCon = NULL;
|
||||
static SctData *queueData = NULL;
|
||||
|
||||
static struct {
|
||||
char *name;
|
||||
@ -179,6 +179,7 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
|
||||
return 0;
|
||||
}
|
||||
UpdateHipadabaPar(node, v, con);
|
||||
ReleaseHdbValue(&v);
|
||||
SetHdbProperty(node, "geterror", NULL);
|
||||
return 1;
|
||||
}
|
||||
@ -187,6 +188,9 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
|
||||
* print
|
||||
*/
|
||||
if (strcmp(argv[1], "print") == 0) {
|
||||
if (queueData != NULL) {
|
||||
queueData->answered = 1;
|
||||
}
|
||||
Arg2Text(argc - 2, argv + 2, value, sizeof value);
|
||||
SCWrite(con, value, eLog);
|
||||
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 (argc < 3) {
|
||||
@ -248,7 +252,7 @@ int SctCallInContext(SConnection * con, char *script, Hdb * node,
|
||||
|
||||
PushContext(node, controller->node);
|
||||
if (verbose) {
|
||||
SCPrintf(con, eLog, "\nscript: %s\n", script);
|
||||
SCPrintf(con, eLog, "script: %s", script);
|
||||
}
|
||||
|
||||
MacroPush(con);
|
||||
@ -257,7 +261,7 @@ int SctCallInContext(SConnection * con, char *script, Hdb * node,
|
||||
result = (char *) Tcl_GetStringResult(pTcl);
|
||||
if (ret != TCL_OK && result[0] != '\0') {
|
||||
if (verbose) {
|
||||
SCPrintf(con, eLog, "\nerror: %s\n", result);
|
||||
SCPrintf(con, eLog, "error: %s", result);
|
||||
}
|
||||
iRet = 0;
|
||||
}
|
||||
@ -276,26 +280,38 @@ static int SctMatch(void *data1, void *data2)
|
||||
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;
|
||||
Hdb *node = data->node;
|
||||
SctController *controller = data->controller;
|
||||
char *state;
|
||||
char *result;
|
||||
char *script;
|
||||
char *script = NULL;
|
||||
char *errorScript = NULL;
|
||||
char *send = NULL;
|
||||
int i;
|
||||
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];
|
||||
|
||||
if (currentCon) {
|
||||
con = currentCon;
|
||||
if (queueData != NULL && queueData->conCtx != NULL) {
|
||||
con = queueData->conCtx;
|
||||
} else {
|
||||
con = controller->conn;
|
||||
}
|
||||
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);
|
||||
}
|
||||
state = GetProp(node, controller->node, "state");
|
||||
@ -304,29 +320,75 @@ static char *SctActionHandler(void *actionData, char *lastReply)
|
||||
SetProp(node, controller->node, "state", state);
|
||||
}
|
||||
for (i = 0; i < 10; i++) {
|
||||
SetProp(node, controller->node, "sent",
|
||||
GetProp(node, controller->node, "send"));
|
||||
SetProp(node, controller->node, "send", NULL);
|
||||
script = GetProp(node, controller->node, state);
|
||||
if (script == NULL)
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
state = result;
|
||||
if (strcasecmp(state, "idle") == 0) {
|
||||
if (currentCon && !data->answered) {
|
||||
SCWrite(con, "o.k.", eValue);
|
||||
if (strcasecmp(state, "idle") == 0 || strcasecmp(state, "unpoll") == 0) {
|
||||
if (queueData == data && !data->answered) {
|
||||
SCWrite(con, "o.k.", eStatus);
|
||||
}
|
||||
if (strcmp(data->name, "write") == 0) {
|
||||
SetHdbProperty(data->node, "writestatus", "commandsent");
|
||||
snprintf(eprop, sizeof eprop, "error_during_%s", data->name);
|
||||
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(timeVal, 50, "%.3f", DoubleTime());
|
||||
snprintf(timeKey, sizeof timeKey, "%s_time", data->name);
|
||||
snprintf(timeVal, sizeof timeVal, "%.3f", DoubleTime());
|
||||
SetHdbProperty(data->node, timeKey, timeVal);
|
||||
send = NULL;
|
||||
goto finish;
|
||||
}
|
||||
SetProp(node, controller->node, "state", state);
|
||||
free(script);
|
||||
script = NULL;
|
||||
send = GetProp(node, controller->node, "send");
|
||||
if (send != NULL && send[0] != '\0') {
|
||||
if (controller->verbose) {
|
||||
@ -337,6 +399,16 @@ static char *SctActionHandler(void *actionData, char *lastReply)
|
||||
}
|
||||
SCPrintf(con, eLogError, "ERROR: too many quick scripts chained");
|
||||
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");
|
||||
if (data->conCtx != NULL) {
|
||||
SCDeleteConnection(data->conCtx);
|
||||
@ -345,16 +417,17 @@ finish:
|
||||
return send;
|
||||
}
|
||||
|
||||
static char *SctWriteHandler(void *actionData, char *lastReply)
|
||||
static char *SctWriteHandler(void *actionData, char *lastReply,
|
||||
int commError)
|
||||
{
|
||||
SctData *data = actionData;
|
||||
SConnection *old;
|
||||
SctData *old;
|
||||
char *result;
|
||||
|
||||
old = currentCon;
|
||||
currentCon = data->conCtx;
|
||||
result = SctActionHandler(data, lastReply);
|
||||
currentCon = old;
|
||||
old = queueData;
|
||||
queueData = data;
|
||||
result = SctActionHandler(data, lastReply, commError);
|
||||
queueData = old;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -379,6 +452,10 @@ static hdbCallbackReturn SctMainCallback(Hdb * node, void *userData,
|
||||
char *geterror;
|
||||
char error[256];
|
||||
|
||||
if (controller->devser == NULL) {
|
||||
/* defunct controller */
|
||||
return hdbContinue;
|
||||
}
|
||||
pm = GetKillPtrMessage(msg);
|
||||
if (pm != NULL) {
|
||||
if (controller == pm->pPtr) {
|
||||
@ -440,7 +517,6 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData,
|
||||
char *writeprio;
|
||||
char *error;
|
||||
SConnection *con;
|
||||
SConnection *con2;
|
||||
char path[MAX_HDB_PATH];
|
||||
|
||||
pm = GetKillPtrMessage(msg);
|
||||
@ -510,16 +586,16 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData,
|
||||
|
||||
mm = GetHdbUpdateMessage(msg);
|
||||
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;
|
||||
GetHdbPath(node, path, sizeof path);
|
||||
con = currentCon;
|
||||
text = formatValue(*(mm->v), node);
|
||||
/* Markus: who is receiving this message?
|
||||
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);
|
||||
}
|
||||
return hdbContinue;
|
||||
@ -577,7 +653,9 @@ static void SctKillCBData(void *d)
|
||||
{
|
||||
SctData *data = d;
|
||||
|
||||
if (data->controller->devser != NULL) {
|
||||
DevRemoveAction(data->controller->devser, data);
|
||||
}
|
||||
SctKillData(d);
|
||||
}
|
||||
|
||||
@ -866,7 +944,8 @@ static void KillSctTransact(void *data)
|
||||
free(self);
|
||||
}
|
||||
|
||||
static char *TransactionHandler(void *actionData, char *lastReply)
|
||||
static char *TransactionHandler(void *actionData, char *lastReply,
|
||||
int commError)
|
||||
{
|
||||
pSctTransact st = (pSctTransact) actionData;
|
||||
|
||||
@ -976,6 +1055,12 @@ static hdbCallbackReturn SctDebugCallback(Hdb * node, void *userData,
|
||||
return hdbContinue;
|
||||
}
|
||||
|
||||
static int SctDeferredFree(void *data)
|
||||
{
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void SctKillController(void *c)
|
||||
{
|
||||
SctController *controller = c;
|
||||
@ -987,41 +1072,47 @@ static void SctKillController(void *c)
|
||||
SCDeleteConnection(controller->conn);
|
||||
}
|
||||
DevKill(controller->devser);
|
||||
controller->devser = NULL;
|
||||
if (pServ->pTasker) {
|
||||
TaskRegister(pServ->pTasker, SctDeferredFree, NULL, NULL, controller,
|
||||
0);
|
||||
} else {
|
||||
free(controller);
|
||||
}
|
||||
}
|
||||
|
||||
static int SctMakeController(SConnection * con, SicsInterp * sics,
|
||||
void *object, int argc, char *argv[])
|
||||
{
|
||||
SICSOBJ *ccmd;
|
||||
Hdb *parent, *par, *cmd;
|
||||
char *nodeName;
|
||||
char *objName;
|
||||
hdbCallback *cb;
|
||||
SctController *controller;
|
||||
|
||||
if (argc < 2) {
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Install into the Hipadaba when full path given
|
||||
*/
|
||||
if(strstr(argv[1],"/") != NULL){
|
||||
parent = FindHdbParent(NULL, argv[1], &nodeName, con);
|
||||
if (strchr(argv[1], '/') == NULL) {
|
||||
/* object name only -> do not anchor in tree */
|
||||
parent = NULL;
|
||||
objName = argv[1];
|
||||
} else {
|
||||
/* full path given -> install into the hipadaba */
|
||||
parent = FindHdbParent(NULL, argv[1], &objName, con);
|
||||
if (parent == NULL)
|
||||
return 0; /* error message already written */
|
||||
} else {
|
||||
nodeName = argv[1];
|
||||
parent = NULL;
|
||||
}
|
||||
|
||||
controller = calloc(1, sizeof(*controller));
|
||||
assert(controller);
|
||||
controller->verbose = 0;
|
||||
|
||||
ccmd = MakeSICSOBJv(nodeName, "SctController", HIPNONE, usSpy);
|
||||
ccmd = MakeSICSOBJv(objName, "SctController", HIPNONE, usSpy);
|
||||
controller->node = ccmd->objectNode;
|
||||
controller->conn = SCCreateDummyConnection(pServ->pSics);
|
||||
|
||||
@ -1038,7 +1129,8 @@ static int SctMakeController(SConnection * con, SicsInterp * sics,
|
||||
if (!controller->devser)
|
||||
return 0;
|
||||
|
||||
AddCommand(pServ->pSics, nodeName, InvokeSICSOBJ, KillSICSOBJ, ccmd);
|
||||
AddCommand(pServ->pSics, objName, InterInvokeSICSOBJ, KillSICSOBJ, ccmd);
|
||||
RegisterSICSOBJKillCmd(ccmd, objName);
|
||||
SetDescriptorKey(ccmd->pDes, "creationCommand", "0");
|
||||
|
||||
cmd = AddSICSHdbPar(controller->node,
|
||||
|
@ -306,8 +306,9 @@ int SctMakeDriveAdapter(SConnection * pCon, SicsInterp * pSics,
|
||||
}
|
||||
|
||||
if (argc < 4) {
|
||||
SCWrite(pCon, "ERROR: not enough arguments for SctMakeDriveAdapter",
|
||||
eError);
|
||||
SCPrintf(pCon, eError,
|
||||
"ERROR: should be %s <object name> <existing-node> <controller>",
|
||||
argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -335,12 +336,8 @@ int SctMakeDriveAdapter(SConnection * pCon, SicsInterp * pSics,
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------*/
|
||||
int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics,
|
||||
void *object, int argc, char *argv[]);
|
||||
|
||||
void SctDriveInit(void)
|
||||
void SctDriveAdapterInit(void)
|
||||
{
|
||||
AddCmd("makesctdrive", SctMakeDriveAdapter);
|
||||
AddCmd("dynsctdrive", SctMakeDriveAdapter);
|
||||
AddCmd("makesctdriveobj", SctMakeDriveObject);
|
||||
}
|
||||
|
118
sctdriveobj.c
118
sctdriveobj.c
@ -3,6 +3,19 @@
|
||||
* scriptcontext to control the actual driving operation. This can also
|
||||
* 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
|
||||
*
|
||||
* Mark Koennecke, June-July 2008
|
||||
@ -34,6 +47,7 @@ static void KillDrivePriv(void *data)
|
||||
}
|
||||
free(priv);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------*/
|
||||
static void *SCTDRIVGetInterface(void *data, int iD)
|
||||
{
|
||||
@ -133,6 +147,8 @@ static long SCTDRIVSetValue(void *data, SConnection * pCon, float val)
|
||||
}
|
||||
pPriv->pCon = SCCopyConnection(pCon);
|
||||
|
||||
StopByData(pServ->pExecutor, data);
|
||||
|
||||
v.dataType = HIPFLOAT;
|
||||
v.v.doubleValue = (double) val;
|
||||
SetHdbProperty(self->objectNode, "writestatus", "start");
|
||||
@ -258,24 +274,17 @@ static void KillDriveOBJ(void *data)
|
||||
}
|
||||
|
||||
pPriv = (pDrivObjPriv) self->pPrivate;
|
||||
if (pPriv->doNotKillNode && self->pDes != NULL) {
|
||||
if (self->pDes->name)
|
||||
free(self->pDes->name);
|
||||
if (self->pDes->pKeys)
|
||||
IFDeleteOptions(self->pDes->pKeys);
|
||||
free(self->pDes);
|
||||
} else {
|
||||
DeleteDescriptor(self->pDes); /* kill descriptor including node */
|
||||
if (pPriv->doNotKillNode && GetDescriptorKey(self->pDes, "creationCommand") == NULL /* it's not a dynamic object */
|
||||
&& self->pDes != NULL) {
|
||||
self->objectNode = NULL; /* do not call RemoveHdbNodeFromParent in KillSICSOBJ */
|
||||
self->pDes->parNode = NULL; /* do not kill the node in KillSICSOBJ/DeleteDescriptor */
|
||||
}
|
||||
if (self->KillPrivate != NULL && self->pPrivate != NULL) {
|
||||
self->KillPrivate(self->pPrivate);
|
||||
}
|
||||
RemoveHdbNodeFromParent(self->objectNode, pServ->dummyCon);
|
||||
free(self);
|
||||
KillSICSOBJ(self);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController * c)
|
||||
pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController * c,
|
||||
int doNotKillNode)
|
||||
{
|
||||
pSICSOBJ pNew = NULL;
|
||||
pDrivObjPriv pPriv = NULL;
|
||||
@ -299,6 +308,7 @@ pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController * c)
|
||||
pNew->objectNode = node;
|
||||
AssignSctDrive(pPriv->pDriv);
|
||||
pPriv->c = c;
|
||||
pPriv->doNotKillNode = doNotKillNode;
|
||||
pNew->pDes->parNode = pNew->objectNode;
|
||||
pNew->pDes->GetInterface = SCTDRIVGetInterface;
|
||||
pNew->pPrivate = pPriv;
|
||||
@ -309,7 +319,7 @@ pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController * c)
|
||||
/*--------------------------------------------------------------------------
|
||||
* This actually has two syntaxes:
|
||||
* 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,
|
||||
void *object, int argc, char *argv[])
|
||||
@ -319,54 +329,58 @@ int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics,
|
||||
pSICSOBJ pNew = NULL;
|
||||
pSICSOBJ pSct = NULL;
|
||||
SctController *c = NULL;
|
||||
int priv, type, status;
|
||||
int priv, type, status, doNotKillNode;
|
||||
hdbValue val;
|
||||
char *sctName;
|
||||
char *class;
|
||||
|
||||
if (argc < 5) {
|
||||
SCWrite(pCon, "ERROR: not enough arguments to SctMakeDriveObject",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
if (argc < 5)
|
||||
goto Usage;
|
||||
|
||||
if (argc == 5) {
|
||||
node = FindHdbNode(NULL, argv[2], pCon);
|
||||
if (node != NULL) {
|
||||
pSct = FindCommandData(pSics, argv[4], "SctController");
|
||||
if (pSct == NULL) {
|
||||
SCPrintf(pCon, eError, "ERROR: SctController %s not found", argv[4]);
|
||||
return 0;
|
||||
if (node == NULL) {
|
||||
SCPrintf(pCon, eError, "ERROR: node %s not found", argv[2]);
|
||||
goto Usage;
|
||||
}
|
||||
c = (SctController *) pSct->pPrivate;
|
||||
pNew = MakeSctDriveObj(node, argv[3], c);
|
||||
pPriv = (pDrivObjPriv) pNew->pPrivate;
|
||||
pPriv->doNotKillNode = 1; /* the node is owned by someone else */
|
||||
sctName = argv[4];
|
||||
class = argv[3];
|
||||
doNotKillNode = 1; /* the node is owned by someone else */
|
||||
} else {
|
||||
/* convert datatype */
|
||||
type = convertHdbType(argv[2]);
|
||||
/* convert privilege */
|
||||
priv = decodeSICSPriv(argv[3]);
|
||||
/* convert datatype */
|
||||
strtolower(argv[4]);
|
||||
type = convertHdbType(argv[2]);
|
||||
if (type == HIPNONE) {
|
||||
node = MakeHipadabaNode(argv[1], HIPNONE, 1);
|
||||
} else {
|
||||
val = makeHdbValue(type, 0);
|
||||
node = MakeSICSHdbPar(argv[1], priv, val);
|
||||
ReleaseHdbValue(&val);
|
||||
}
|
||||
if (priv < 0 || type != HIPFLOAT)
|
||||
goto Usage;
|
||||
node = MakeSICSHdbPar(argv[1], priv, MakeHdbFloat(0.0));
|
||||
if (node == NULL) {
|
||||
SCWrite(pCon, "ERROR: node creation failed", eError);
|
||||
return 0;
|
||||
}
|
||||
c = FindCommandData(pSics, argv[5], "SctController");
|
||||
if (c == NULL) {
|
||||
SCPrintf(pCon, eError, "ERROR: SctController %s not found", argv[4]);
|
||||
return 0;
|
||||
sctName = argv[5];
|
||||
class = argv[4];
|
||||
doNotKillNode = 0; /* kill the node with the command */
|
||||
}
|
||||
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) {
|
||||
SCWrite(pCon, "ERROR: failed to create drive object", eError);
|
||||
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,
|
||||
argv[1], InterInvokeSICSOBJ, KillDriveOBJ, pNew);
|
||||
if (status != 1) {
|
||||
@ -376,4 +390,18 @@ int SctMakeDriveObject(SConnection * pCon, SicsInterp * pSics,
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -1346,6 +1346,7 @@ static void SICSDeleteNodeData(pHdb node)
|
||||
}
|
||||
|
||||
removeNodeFromUpdateList(node);
|
||||
DeleteCallbackChain(node);
|
||||
while (node->child != NULL) {
|
||||
tmp = node->child;
|
||||
node->child = node->child->next;
|
||||
@ -1354,7 +1355,6 @@ static void SICSDeleteNodeData(pHdb node)
|
||||
if (node->properties != NULL) {
|
||||
DeleteStringDict(node->properties);
|
||||
}
|
||||
DeleteCallbackChain(node);
|
||||
|
||||
if (node->name != NULL) {
|
||||
free(node->name);
|
||||
@ -1616,7 +1616,7 @@ static int RemoveParNodeCallback(char *name, pDummy object,
|
||||
|
||||
m.type = killPtr;
|
||||
m.pPtr = internalID;
|
||||
if (object->pDescriptor->parNode) {
|
||||
if (object && object->pDescriptor->parNode) {
|
||||
RecurseCallbackChains(object->pDescriptor->parNode, (pHdbMessage) & m);
|
||||
}
|
||||
return 1;
|
||||
@ -1805,7 +1805,8 @@ int ProcessSICSHdbPar(pHdb root, SConnection * pCon,
|
||||
SCWrite(pCon, "ERROR: out of memory processing parameter", eError);
|
||||
return 0;
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
DynStringConcat(parData, argv[1]);
|
||||
for (i = 2; i < argc; i++) {
|
||||
DynStringConcat(parData, " ");
|
||||
DynStringConcat(parData, argv[i]);
|
||||
}
|
||||
@ -2048,7 +2049,7 @@ int readHdbValue(hdbValue * v, char *data, char *error, int errlen)
|
||||
getNextHdbNumber(data, number);
|
||||
status = sscanf(number, "%d", &v->v.intValue);
|
||||
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;
|
||||
}
|
||||
break;
|
||||
@ -2056,7 +2057,7 @@ int readHdbValue(hdbValue * v, char *data, char *error, int errlen)
|
||||
getNextHdbNumber(data, number);
|
||||
status = sscanf(number, "%lf", &v->v.doubleValue);
|
||||
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;
|
||||
}
|
||||
break;
|
||||
@ -2082,7 +2083,7 @@ int readHdbValue(hdbValue * v, char *data, char *error, int errlen)
|
||||
}
|
||||
status = sscanf(number, "%d", &lValue);
|
||||
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;
|
||||
}
|
||||
v->v.intArray[i] = lValue;
|
||||
@ -2104,7 +2105,7 @@ int readHdbValue(hdbValue * v, char *data, char *error, int errlen)
|
||||
}
|
||||
status = sscanf(number, "%lf", &dValue);
|
||||
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;
|
||||
}
|
||||
v->v.floatArray[i] = dValue;
|
||||
@ -2154,7 +2155,7 @@ int convertHdbType(char *text)
|
||||
|
||||
type = 0;
|
||||
while (hdbTypes[type] != NULL) {
|
||||
if (strcmp(hdbTypes[type], text) == 0) {
|
||||
if (strcasecmp(hdbTypes[type], text) == 0) {
|
||||
break;
|
||||
}
|
||||
type++;
|
||||
@ -2196,7 +2197,6 @@ static int MakeHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
/*
|
||||
* convert datatype
|
||||
*/
|
||||
strtolower(argv[3]);
|
||||
type = convertHdbType(argv[3]);
|
||||
if (type > HIPFLOATVARAR) {
|
||||
SCWrite(pCon,
|
||||
@ -2210,7 +2210,7 @@ static int MakeHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
eError);
|
||||
return 0;
|
||||
} 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);
|
||||
return 0;
|
||||
}
|
||||
for (i = 2; i < argc; i++) {
|
||||
DynStringConcat(parData, argv[2]);
|
||||
for (i = 3; i < argc; i++) {
|
||||
DynStringConcat(parData, " ");
|
||||
DynStringConcat(parData, argv[i]);
|
||||
}
|
||||
@ -3310,7 +3311,7 @@ static int GetSICSHdbProperty(SConnection * pCon, SicsInterp * pSics,
|
||||
}
|
||||
status = GetHdbProperty(targetNode, argv[2], buffer, 511);
|
||||
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;
|
||||
}
|
||||
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);
|
||||
if (targetNode == NULL) {
|
||||
SCWrite(pCon, "ERROR: node not found", eValue);
|
||||
SCWrite(pCon, "ERROR: node not found", eError);
|
||||
return 0;
|
||||
}
|
||||
status = GetHdbProperty(targetNode, argv[2], buffer, 511);
|
||||
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;
|
||||
}
|
||||
SCPrintf(pCon, eValue, "%s", buffer);
|
||||
|
@ -284,6 +284,10 @@ int GetHdbPath(pHdb nodeArg, char *path, size_t pathlen);
|
||||
* @param internalID the internalID to be looked for
|
||||
*/
|
||||
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.
|
||||
* @param obj The object for which to get a parameter.
|
||||
|
55
sicsobj.c
55
sicsobj.c
@ -17,7 +17,11 @@
|
||||
#include "initializer.h"
|
||||
#include "splitter.h"
|
||||
|
||||
extern int decodeSICSPriv(char *txt); /* from access.c */
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *class;
|
||||
} NameClass;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void DefaultKill(void *data)
|
||||
{
|
||||
@ -74,6 +78,42 @@ int SaveSICSOBJ(void *data, char *name, FILE * fd)
|
||||
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)
|
||||
{
|
||||
@ -119,8 +159,11 @@ void KillSICSOBJ(void *data)
|
||||
if (self->KillPrivate != NULL && self->pPrivate != NULL) {
|
||||
self->KillPrivate(self->pPrivate);
|
||||
}
|
||||
if (self->objectNode != NULL) {
|
||||
RemoveHdbNodeFromParent(self->objectNode, pServ->dummyCon);
|
||||
}
|
||||
if (self->pDes != NULL) {
|
||||
self->objectNode = NULL; /* inhibit SICSOBJcallback from deleting twice */
|
||||
DeleteDescriptor(self->pDes); /* kill descriptor including node */
|
||||
}
|
||||
free(self);
|
||||
@ -412,11 +455,11 @@ int InterInvokeSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
if (status == -1) {
|
||||
status = 0;
|
||||
if (argc > 1) {
|
||||
snprintf(buffer, 131,
|
||||
"ERROR: no command or parameter found for key: %s",
|
||||
argv[1]);
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"ERROR: %s %s not found",
|
||||
argv[0], argv[1]);
|
||||
} else {
|
||||
snprintf(buffer, 131, "ERROR: no argument found");
|
||||
snprintf(buffer, sizeof buffer, "ERROR: no argument found");
|
||||
}
|
||||
SCWrite(pCon, buffer, eError);
|
||||
status = 0;
|
||||
@ -444,7 +487,6 @@ pSICSOBJ SetupSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
/* convert privilege */
|
||||
priv = decodeSICSPriv(argv[3]);
|
||||
/* convert datatype */
|
||||
strtolower(argv[4]);
|
||||
type = convertHdbType(argv[4]);
|
||||
if (type > HIPFLOAT) {
|
||||
SCWrite(pCon,
|
||||
@ -464,6 +506,7 @@ pSICSOBJ SetupSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
SetDescriptorKey(pNew->pDes, "creationCommand", "0");
|
||||
}
|
||||
|
||||
SetHdbProperty(pNew->objectNode, "objectName", argv[1]);
|
||||
status = AddCommand(pSics,
|
||||
argv[1], InterInvokeSICSOBJ, KillSICSOBJ, pNew);
|
||||
if (status != 1) {
|
||||
|
@ -31,6 +31,9 @@ void KillSICSOBJ(void *data);
|
||||
void DefaultKill(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);
|
||||
|
||||
/**
|
||||
|
11
stringdict.c
11
stringdict.c
@ -259,6 +259,12 @@ const char *StringDictGetNext(pStringDict self, char *pValue, int iValLen)
|
||||
} else {
|
||||
LLDnodeDataTo(self->iList, &sVal);
|
||||
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;
|
||||
}
|
||||
} else { /* start a new one */
|
||||
@ -270,6 +276,11 @@ const char *StringDictGetNext(pStringDict self, char *pValue, int iValLen)
|
||||
self->iTraverse = 1;
|
||||
LLDnodeDataTo(self->iList, &sVal);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
27
task.c
27
task.c
@ -344,3 +344,30 @@ int TaskContinue(pTaskMan self)
|
||||
self->iStop = 0;
|
||||
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;
|
||||
}
|
||||
|
4
task.h
4
task.h
@ -113,5 +113,9 @@ int TaskSignal(pTaskMan self, int iSignal, void *pSigData);
|
||||
pSigData.
|
||||
*/
|
||||
/*-------------------------------------------------------------------------*/
|
||||
void TaskRemove(pTaskMan self, TaskFunc pTaskRun, void *pData);
|
||||
/*
|
||||
remove the task with the given task function and the given data pointer
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user