- 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 */
|
/* 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,8 +1048,7 @@ 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)
|
||||||
{
|
{
|
||||||
|
128
ascon.c
128
ascon.c
@ -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
|
||||||
*/
|
*/
|
||||||
@ -63,7 +65,7 @@ double DoubleTime(void)
|
|||||||
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",
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
@ -97,10 +105,22 @@ static void AsconConnect(Ascon * a)
|
|||||||
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,7 +139,6 @@ 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 =
|
||||||
@ -132,7 +151,7 @@ static void AsconConnect(Ascon * a)
|
|||||||
a->state = AsconConnecting;
|
a->state = AsconConnecting;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
AsconError(a, "connect failed:", errno);
|
AsconError(a, "ASC2", errno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,7 +163,6 @@ 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]);
|
||||||
@ -156,6 +174,10 @@ int AsconStdInit(Ascon * a, SConnection * con, int argc, char *argv[])
|
|||||||
} 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.
|
||||||
@ -348,22 +381,32 @@ int AsconStdHandler(Ascon * a)
|
|||||||
while (ret > 0) {
|
while (ret > 0) {
|
||||||
a->start = DoubleTime();
|
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 (chr == '\n') {
|
||||||
if (a->readState) {
|
if (a->readState) { /* last char was CR */
|
||||||
/* swallow LF after CR */
|
/* swallow LF after CR */
|
||||||
DynStringClear(a->rdBuffer);
|
|
||||||
a->readState = 0;
|
a->readState = 0;
|
||||||
|
chr = 0;
|
||||||
} else {
|
} else {
|
||||||
DynStringConcatChar(a->rdBuffer, '\0');
|
DynStringConcatChar(a->rdBuffer, '\0');
|
||||||
a->state = AsconReadDone;
|
a->state = AsconReadDone;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (chr == '\r') {
|
} else if (chr == '\r') {
|
||||||
a->readState = 1;
|
a->readState = 1; /* set 'last char was CR' */
|
||||||
DynStringConcatChar(a->rdBuffer, '\0');
|
DynStringConcatChar(a->rdBuffer, '\0');
|
||||||
a->state = AsconReadDone;
|
a->state = AsconReadDone;
|
||||||
break;
|
break;
|
||||||
} else {
|
}
|
||||||
|
}
|
||||||
|
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,27 +427,23 @@ 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,
|
||||||
@ -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);
|
||||||
/* allow the system to cleanup the socket, otherwise a reconnect will fail */
|
lastClose = DoubleTime();
|
||||||
sleep(1);
|
|
||||||
a->fd = -1;
|
a->fd = -1;
|
||||||
a->state = AsconConnectStart;
|
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
15
ascon.h
@ -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
14
ascon.i
@ -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
|
||||||
*/
|
*/
|
||||||
|
22
commandlog.c
22
commandlog.c
@ -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 (iCompact == 1) {
|
||||||
|
nowTm = localtime(&now);
|
||||||
|
strftime(stamp1, sizeof stamp1, "%H:%M:%S", nowTm);
|
||||||
|
if (prompt == NULL)
|
||||||
|
prompt = "";
|
||||||
if (id == NOID) {
|
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;
|
||||||
|
39
devexec.c
39
devexec.c
@ -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[])
|
||||||
|
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,
|
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 -----------------------------------------*/
|
||||||
|
12
devexec.tex
12
devexec.tex
@ -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]
|
||||||
|
@ -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);
|
||||||
/*
|
/*
|
||||||
|
47
devser.c
47
devser.c
@ -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;
|
||||||
}
|
}
|
||||||
@ -364,8 +376,9 @@ int DevRemoveAction(DevSer * devser, void *actionData)
|
|||||||
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 */
|
||||||
|
14
devser.h
14
devser.h
@ -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
|
||||||
|
21
errormsg.c
21
errormsg.c
@ -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,6 +34,7 @@ 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);
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
20
errormsg.h
20
errormsg.h
@ -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
|
||||||
|
@ -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
25
macro.c
@ -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) {
|
||||||
|
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 \
|
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 \
|
||||||
|
25
motor.c
25
motor.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
51
network.c
51
network.c
@ -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);
|
||||||
|
if (self->sockid != 0) {
|
||||||
close(self->sockid);
|
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) {
|
||||||
|
@ -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-
|
||||||
|
@ -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
5
ofac.c
@ -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);
|
||||||
|
42
script.c
42
script.c
@ -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;
|
||||||
|
}
|
||||||
|
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 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
|
||||||
|
176
scriptcontext.c
176
scriptcontext.c
@ -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;
|
||||||
|
|
||||||
|
if (data->controller->devser != NULL) {
|
||||||
DevRemoveAction(data->controller->devser, data);
|
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,41 +1072,47 @@ static void SctKillController(void *c)
|
|||||||
SCDeleteConnection(controller->conn);
|
SCDeleteConnection(controller->conn);
|
||||||
}
|
}
|
||||||
DevKill(controller->devser);
|
DevKill(controller->devser);
|
||||||
|
controller->devser = NULL;
|
||||||
|
if (pServ->pTasker) {
|
||||||
|
TaskRegister(pServ->pTasker, SctDeferredFree, NULL, NULL, controller,
|
||||||
|
0);
|
||||||
|
} else {
|
||||||
free(controller);
|
free(controller);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int SctMakeController(SConnection * con, SicsInterp * sics,
|
static int SctMakeController(SConnection * con, SicsInterp * sics,
|
||||||
void *object, int argc, char *argv[])
|
void *object, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
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);
|
} else {
|
||||||
|
/* full path given -> install into the hipadaba */
|
||||||
|
parent = FindHdbParent(NULL, argv[1], &objName, con);
|
||||||
if (parent == NULL)
|
if (parent == NULL)
|
||||||
return 0; /* error message already written */
|
return 0; /* error message already written */
|
||||||
} else {
|
|
||||||
nodeName = argv[1];
|
|
||||||
parent = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
@ -1038,7 +1129,8 @@ static int SctMakeController(SConnection * con, SicsInterp * sics,
|
|||||||
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,
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
118
sctdriveobj.c
118
sctdriveobj.c
@ -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
|
||||||
@ -34,6 +47,7 @@ static void KillDrivePriv(void *data)
|
|||||||
}
|
}
|
||||||
free(priv);
|
free(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------*/
|
/*---------------------------------------------------------------*/
|
||||||
static void *SCTDRIVGetInterface(void *data, int iD)
|
static void *SCTDRIVGetInterface(void *data, int iD)
|
||||||
{
|
{
|
||||||
@ -133,6 +147,8 @@ static long SCTDRIVSetValue(void *data, SConnection * pCon, float val)
|
|||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (argc == 5) {
|
||||||
node = FindHdbNode(NULL, argv[2], pCon);
|
node = FindHdbNode(NULL, argv[2], pCon);
|
||||||
if (node != NULL) {
|
if (node == NULL) {
|
||||||
pSct = FindCommandData(pSics, argv[4], "SctController");
|
SCPrintf(pCon, eError, "ERROR: node %s not found", argv[2]);
|
||||||
if (pSct == NULL) {
|
goto Usage;
|
||||||
SCPrintf(pCon, eError, "ERROR: SctController %s not found", argv[4]);
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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.
|
||||||
|
55
sicsobj.c
55
sicsobj.c
@ -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);
|
||||||
}
|
}
|
||||||
|
if (self->objectNode != NULL) {
|
||||||
RemoveHdbNodeFromParent(self->objectNode, pServ->dummyCon);
|
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) {
|
||||||
|
@ -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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
11
stringdict.c
11
stringdict.c
@ -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
27
task.c
@ -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;
|
||||||
|
}
|
||||||
|
4
task.h
4
task.h
@ -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
|
||||||
|
Reference in New Issue
Block a user