Merge branch 'master' into maverick
This commit is contained in:
82
SICSmain.c
82
SICSmain.c
@ -20,19 +20,25 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "nserver.h"
|
||||
#include "servlog.h"
|
||||
|
||||
extern void KeepStartupCommands(); /* ofac.c */
|
||||
|
||||
/***************************** Necessary Globals ****************************/
|
||||
|
||||
IPair *pSICSOptions = NULL;
|
||||
pServer pServ = NULL;
|
||||
|
||||
/* ========================= Less dreadful file statics =================== */
|
||||
|
||||
#define DEFAULTINIFILE "servo.tcl"
|
||||
|
||||
int usage(const char *name)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-d] [-nolog] <config.tcl>\n", name);
|
||||
fprintf(stderr, " -d: daemonize the process\n");
|
||||
fprintf(stderr, " -nolog: disable log file writing\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
The Servers Main program. May take one argument: the name of an
|
||||
initialisation file
|
||||
@ -41,25 +47,54 @@ pServer pServ = NULL;
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int iRet;
|
||||
int daemonize = 0;
|
||||
char *file = NULL;
|
||||
int i;
|
||||
int i, firstArg = 1;
|
||||
extern pServer pServ;
|
||||
char *argv0;
|
||||
|
||||
argv0 = argv[0];
|
||||
if (argc < 2)
|
||||
return usage(argv[0]);
|
||||
|
||||
/* initialise, will die on you if problems */
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-nolog") == 0) {
|
||||
SICSLogEnable(0);
|
||||
}else if(strcmp(argv[i],"-keepstartup") == 0){
|
||||
KeepStartupCommands();
|
||||
|
||||
for (i = firstArg; i < argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
if (strcasecmp(argv[i], "-nolog") == 0) {
|
||||
SICSLogEnable(0);
|
||||
}else if(strcmp(argv[i],"-keepstartup") == 0){
|
||||
KeepStartupCommands();
|
||||
#ifdef SITE_ANSTO
|
||||
} else if (strcasecmp(argv[i], "-v") == 0) {
|
||||
extern void SiteReportVersion(void);
|
||||
SiteReportVersion();
|
||||
return 0;
|
||||
#endif
|
||||
} else if (strcasecmp(argv[i], "-d") == 0) {
|
||||
daemonize = 1;
|
||||
} else {
|
||||
fprintf(stderr, "Unrecognized option ignored: %s\n", argv[i]);
|
||||
}
|
||||
} else if (file == NULL) {
|
||||
file = argv[i];
|
||||
} else {
|
||||
fprintf(stderr, "Unrecognized argument ignored: %s\n", argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (file == NULL)
|
||||
return usage(argv[0]);
|
||||
|
||||
iRet = InitServer(file, &pServ);
|
||||
if (!iRet) {
|
||||
printf("Unrecoverable error on server startup, exiting.........\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
if (daemonize == 1)
|
||||
daemon(1, 1);
|
||||
*/
|
||||
|
||||
RunServer(pServ);
|
||||
|
||||
@ -68,28 +103,3 @@ int main(int argc, char *argv[])
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
SicsInterp *GetInterpreter(void)
|
||||
{
|
||||
return pServ->pSics;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
pExeList GetExecutor(void)
|
||||
{
|
||||
return pServ->pExecutor;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
void StopExit(void)
|
||||
{
|
||||
if (pServ) {
|
||||
StopServer(pServ);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
pTaskMan GetTasker(void)
|
||||
{
|
||||
return pServ->pTasker;
|
||||
}
|
||||
|
@ -57,6 +57,10 @@ typedef enum {
|
||||
eLogError /* error message to log: is always written to client */
|
||||
} OutCode;
|
||||
|
||||
const char* OutCodeToTxt(OutCode outcode);
|
||||
const char* OutCodeToText(OutCode outcode);
|
||||
int OutCodeFromText(const char *text, OutCode *outcode);
|
||||
|
||||
#include "interrupt.h"
|
||||
|
||||
/* define some user rights codes */
|
||||
|
15
ascon.c
15
ascon.c
@ -84,6 +84,8 @@ void AsconError(Ascon *a, char *msg, int errorno)
|
||||
DynStringConcat(a->errmsg, " (");
|
||||
DynStringConcat(a->errmsg, state);
|
||||
DynStringConcat(a->errmsg, " state)");
|
||||
DynStringConcat(a->errmsg, " on ");
|
||||
DynStringConcat(a->errmsg, a->hostport);
|
||||
} else {
|
||||
DynStringConcat(a->errmsg, strerror(errorno));
|
||||
DynStringConcat(a->errmsg, " (");
|
||||
@ -91,6 +93,8 @@ void AsconError(Ascon *a, char *msg, int errorno)
|
||||
DynStringConcat(a->errmsg, " state, ");
|
||||
DynStringConcat(a->errmsg, msg);
|
||||
DynStringConcat(a->errmsg, ")");
|
||||
DynStringConcat(a->errmsg, " on ");
|
||||
DynStringConcat(a->errmsg, a->hostport);
|
||||
}
|
||||
a->state = AsconFailed;
|
||||
}
|
||||
@ -262,8 +266,7 @@ int AsconReadChar(int fd, char *chr)
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
ret = recv(fd, chr, 1, 0);
|
||||
/* PrintChar(*chr); */
|
||||
fflush(stdout);
|
||||
/* PrintChar(*chr); fflush(stdout); */
|
||||
if (ret > 0)
|
||||
return 1;
|
||||
if (ret == 0) {
|
||||
@ -388,6 +391,12 @@ int AsconBaseHandler(Ascon * a)
|
||||
}
|
||||
|
||||
void AsconInsertProtocol(AsconProtocol *protocol) {
|
||||
AsconProtocol *p;
|
||||
|
||||
for (p = protocols; p != NULL; p = p->next) {
|
||||
if (p == protocol)
|
||||
return;
|
||||
}
|
||||
protocol->next = protocols;
|
||||
protocols = protocol;
|
||||
}
|
||||
@ -812,7 +821,7 @@ char *AsconRead(Ascon * a)
|
||||
{
|
||||
if (a->noResponse) {
|
||||
a->noResponse = 0;
|
||||
return "";
|
||||
return NULL;
|
||||
}
|
||||
if (a->state != AsconIdle) {
|
||||
a->state = AsconIdle;
|
||||
|
117
asyncprotocol.c
117
asyncprotocol.c
@ -31,16 +31,23 @@ int defaultSendCommand(pAsyncProtocol p, pAsyncTxn txn)
|
||||
int defaultHandleInput(pAsyncProtocol p, pAsyncTxn txn, int ch)
|
||||
{
|
||||
const char *term = "\r\n";
|
||||
if (p->replyTerminator)
|
||||
term = p->replyTerminator;
|
||||
if (ch == term[txn->txn_state])
|
||||
if (txn->txn_state == 0) {
|
||||
int i;
|
||||
for (i = 0; i < 10; ++i)
|
||||
if (p->replyTerminator[i] && ch == p->replyTerminator[i][0]) {
|
||||
txn->txn_state = i << 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
term = p->replyTerminator[txn->txn_state >> 16];
|
||||
if (ch == term[txn->txn_state & 0xffff])
|
||||
++txn->txn_state;
|
||||
else
|
||||
txn->txn_state = 0;
|
||||
|
||||
if (txn->inp_idx < txn->inp_len)
|
||||
txn->inp_buf[txn->inp_idx++] = ch;
|
||||
if (term[txn->txn_state] == 0) {
|
||||
if (term[txn->txn_state & 0xffff] == 0) {
|
||||
if (txn->inp_idx < txn->inp_len)
|
||||
txn->inp_buf[txn->inp_idx] = '\0';
|
||||
return AQU_POP_CMD;
|
||||
@ -64,10 +71,7 @@ int defaultPrepareTxn(pAsyncProtocol p, pAsyncTxn txn, const char *cmd,
|
||||
term = p->sendTerminator;
|
||||
state = 0;
|
||||
for (i = 0; i < cmd_len; ++i) {
|
||||
if (cmd[i] == 0x00) { /* end of transmission */
|
||||
cmd_len = i;
|
||||
break;
|
||||
} else if (cmd[i] == term[state]) {
|
||||
if (cmd[i] == term[state]) {
|
||||
++state;
|
||||
continue;
|
||||
}
|
||||
@ -100,14 +104,6 @@ int defaultPrepareTxn(pAsyncProtocol p, pAsyncTxn txn, const char *cmd,
|
||||
if (txn->inp_buf != NULL) {
|
||||
free(txn->inp_buf);
|
||||
}
|
||||
txn->inp_buf = malloc(rsp_len);
|
||||
if (txn->inp_buf == NULL) {
|
||||
SICSLogWrite("Out of memory in AsyncProtocol::defaultPrepareTxn",
|
||||
eError);
|
||||
free(txn->out_buf);
|
||||
txn->out_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
txn->inp_len = rsp_len;
|
||||
txn->inp_idx = 0;
|
||||
txn->txn_state = 0;
|
||||
@ -122,11 +118,15 @@ static void encodeTerminator(char *result, char *terminator)
|
||||
{
|
||||
if (terminator)
|
||||
while (*terminator) {
|
||||
*result++ = '0';
|
||||
*result++ = 'x';
|
||||
*result++ = hex[(*terminator >> 4) & 0xF];
|
||||
*result++ = hex[(*terminator) & 0xF];
|
||||
++terminator;
|
||||
if (*terminator <= 32 || *terminator >= 127) {
|
||||
*result++ = '0';
|
||||
*result++ = 'x';
|
||||
*result++ = hex[(*terminator >> 4) & 0xF];
|
||||
*result++ = hex[(*terminator) & 0xF];
|
||||
++terminator;
|
||||
} else {
|
||||
*result++ = *terminator++;
|
||||
}
|
||||
}
|
||||
*result = '\0';
|
||||
return;
|
||||
@ -208,7 +208,6 @@ int AsyncProtocolNoAction(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[])
|
||||
{
|
||||
char line[132];
|
||||
pAsyncProtocol self = (pAsyncProtocol) pData;
|
||||
snprintf(line, 132, "%s does not understand %s", argv[0], argv[1]);
|
||||
SCWrite(pCon, line, eError);
|
||||
return 0;
|
||||
@ -217,7 +216,6 @@ int AsyncProtocolNoAction(SConnection * pCon, SicsInterp * pSics,
|
||||
int AsyncProtocolAction(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[])
|
||||
{
|
||||
char line[132];
|
||||
pAsyncProtocol self = (pAsyncProtocol) pData;
|
||||
if (argc > 1) {
|
||||
/* handle genecic parameters like terminators */
|
||||
@ -240,39 +238,54 @@ int AsyncProtocolAction(SConnection * pCon, SicsInterp * pSics,
|
||||
return 1;
|
||||
} else if (strcasecmp(argv[1], "replyterminator") == 0) {
|
||||
if (argc > 2) {
|
||||
char *pPtr = decodeTerminator(argv[2]);
|
||||
if (pPtr) {
|
||||
if (self->replyTerminator)
|
||||
free(self->replyTerminator);
|
||||
self->replyTerminator = pPtr;
|
||||
int i;
|
||||
for (i = 0; i < 10; ++i)
|
||||
if (self->replyTerminator[i]) {
|
||||
free(self->replyTerminator[i]);
|
||||
self->replyTerminator[i] = NULL;
|
||||
}
|
||||
for (i = 0; i < 10 && i < argc - 2; ++i) {
|
||||
char* pPtr = decodeTerminator(argv[i + 2]);
|
||||
if (pPtr) {
|
||||
self->replyTerminator[i] = pPtr;
|
||||
}
|
||||
}
|
||||
SCSendOK(pCon);
|
||||
} else {
|
||||
int i;
|
||||
char term[132];
|
||||
char line[1024];
|
||||
encodeTerminator(term, self->replyTerminator);
|
||||
sprintf(line, "%s.replyTerminator = \"%s\"", argv[0], term);
|
||||
term[0] = '\0';
|
||||
sprintf(line, "%s.replyTerminator =", argv[0]);
|
||||
for (i = 0; i < 10; ++i) {
|
||||
if (self->replyTerminator[i] == NULL)
|
||||
break;
|
||||
term[0] = ' ';
|
||||
term[1] = '"';
|
||||
encodeTerminator(&term[2], self->replyTerminator[i]);
|
||||
strcat(term, "\"");
|
||||
strcat(line, term);
|
||||
}
|
||||
SCWrite(pCon, line, eValue);
|
||||
}
|
||||
return 1;
|
||||
} else if (strcasecmp(argv[1], "list") == 0) {
|
||||
int ac = 2;
|
||||
char *av[3] = { argv[0], 0, 0 };
|
||||
av[1] = "sendterminator";
|
||||
AsyncProtocolAction(pCon, pSics, pData, ac, av);
|
||||
av[1] = "replyterminator";
|
||||
AsyncProtocolAction(pCon, pSics, pData, ac, av);
|
||||
return 1;
|
||||
}
|
||||
} else if (strcasecmp(argv[1], "list") == 0) {
|
||||
int ac = 2;
|
||||
char *av[3] = { argv[0], 0, 0 };
|
||||
av[1] = "sendterminator";
|
||||
AsyncProtocolAction(pCon, pSics, pData, ac, av);
|
||||
av[1] = "replyterminator";
|
||||
AsyncProtocolAction(pCon, pSics, pData, ac, av);
|
||||
return 1;
|
||||
}
|
||||
/* handle any other actions here */
|
||||
}
|
||||
return AsyncProtocolNoAction(pCon, pSics, pData, argc, argv);
|
||||
}
|
||||
|
||||
void defaultKillPrivate(pAsyncProtocol p)
|
||||
{
|
||||
if (p->privateData) {
|
||||
/* TODO: should we do anything? */
|
||||
free(p->privateData);
|
||||
}
|
||||
}
|
||||
@ -280,14 +293,23 @@ void defaultKillPrivate(pAsyncProtocol p)
|
||||
void AsyncProtocolKill(void *pData)
|
||||
{
|
||||
pAsyncProtocol self = (pAsyncProtocol) pData;
|
||||
if (self->pDes)
|
||||
DeleteDescriptor(self->pDes);
|
||||
if (self->sendTerminator != NULL)
|
||||
free(self->sendTerminator);
|
||||
if (self->replyTerminator != NULL)
|
||||
free(self->replyTerminator);
|
||||
int i;
|
||||
if (self->killPrivate)
|
||||
self->killPrivate(self);
|
||||
if (self->pDes)
|
||||
DeleteDescriptor(self->pDes);
|
||||
self->pDes = NULL;
|
||||
if (self->protocolName)
|
||||
free(self->protocolName);
|
||||
self->protocolName = NULL;
|
||||
if (self->sendTerminator != NULL)
|
||||
free(self->sendTerminator);
|
||||
self->sendTerminator = NULL;
|
||||
for (i = 0; i < 10; ++i) {
|
||||
if (self->replyTerminator[i] != NULL)
|
||||
free(self->replyTerminator[i]);
|
||||
self->replyTerminator[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pAsyncProtocol AsyncProtocolCreate(SicsInterp * pSics,
|
||||
@ -322,13 +344,14 @@ pAsyncProtocol AsyncProtocolCreate(SicsInterp * pSics,
|
||||
AsyncProtocolKill(self);
|
||||
return NULL;
|
||||
}
|
||||
self->protocolName = strdup(protocolName);
|
||||
self->sendCommand = defaultSendCommand;
|
||||
self->handleInput = defaultHandleInput;
|
||||
self->handleEvent = defaultHandleEvent;
|
||||
self->prepareTxn = defaultPrepareTxn;
|
||||
self->killPrivate = defaultKillPrivate;
|
||||
self->sendTerminator = strdup("\r\n");
|
||||
self->replyTerminator = strdup("\r\n");
|
||||
self->replyTerminator[0] = strdup("\r\n");
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,12 @@ typedef enum {
|
||||
ATX_DISCO = 3
|
||||
} ATX_STATUS;
|
||||
|
||||
#define AQU_TIMEOUT -1
|
||||
#define AQU_DISCONNECT -2
|
||||
#define AQU_RECONNECT -3
|
||||
#define AQU_RETRY_CMD -4
|
||||
#define AQU_POP_CMD -5
|
||||
|
||||
struct __async_txn {
|
||||
pAsyncUnit unit; /**< unit that transaction is associated with */
|
||||
int txn_state; /**< protocol handler transaction parse state */
|
||||
@ -38,6 +44,8 @@ struct __async_txn {
|
||||
int inp_len; /**< length of input buffer */
|
||||
int inp_idx; /**< index of next character (number already received) */
|
||||
AsyncTxnHandler handleResponse; /**< Txn response handler of command sender */
|
||||
void *proto_private; /**< Protocol Private structure */
|
||||
void (*kill_private) (pAsyncTxn pTxn); /**< if it needs killing */
|
||||
void *cntx; /**< opaque context used by command sender */
|
||||
/* The cntx field may be used by protocol handler from sendCommand
|
||||
* as long as it is restored when response is complete
|
||||
@ -51,7 +59,7 @@ struct __async_protocol {
|
||||
pObjectDescriptor pDes;
|
||||
char *protocolName;
|
||||
char *sendTerminator;
|
||||
char *replyTerminator;
|
||||
char *replyTerminator[10];
|
||||
void *privateData;
|
||||
int (*sendCommand) (pAsyncProtocol p, pAsyncTxn txn);
|
||||
int (*handleInput) (pAsyncProtocol p, pAsyncTxn txn, int ch);
|
||||
|
638
asyncqueue.c
638
asyncqueue.c
@ -8,18 +8,20 @@
|
||||
* single command channel.
|
||||
*
|
||||
* Douglas Clowes, February 2007
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netdb.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <sics.h>
|
||||
#include <rs232controller.h>
|
||||
#include "network.h"
|
||||
#include "asyncqueue.h"
|
||||
#include "nwatch.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
typedef struct __async_command AQ_Cmd, *pAQ_Cmd;
|
||||
@ -40,6 +42,9 @@ struct __AsyncUnit {
|
||||
void *notify_cntx;
|
||||
};
|
||||
|
||||
typedef enum { eAsyncIdle, eAsyncWaiting, eAsyncConnecting,
|
||||
eAsyncConnected } AsyncState;
|
||||
|
||||
struct __AsyncQueue {
|
||||
pObjectDescriptor pDes;
|
||||
char *queue_name;
|
||||
@ -48,6 +53,9 @@ struct __AsyncQueue {
|
||||
int iDelay; /* intercommand delay in milliseconds */
|
||||
int timeout;
|
||||
int retries;
|
||||
int retryTimer; /* mSec delay before next retry */
|
||||
bool translate; /* translate binary output with escaped chars */
|
||||
bool trace;
|
||||
struct timeval tvLastCmd; /* time of completion of last command */
|
||||
int unit_count; /* number of units connected */
|
||||
pAsyncUnit units; /* head of unit chain */
|
||||
@ -56,12 +64,56 @@ struct __AsyncQueue {
|
||||
pNWContext nw_ctx; /* NetWait context handle */
|
||||
pNWTimer nw_tmr; /* NetWait timer handle */
|
||||
mkChannel *pSock; /* socket address */
|
||||
AsyncState state; /* Queue Connection State */
|
||||
pAsyncProtocol protocol;
|
||||
char *noreply_text;
|
||||
int noreply_len;
|
||||
void *context; /**< opaque caller queue context */
|
||||
};
|
||||
|
||||
static pAsyncQueue queue_array[FD_SETSIZE];
|
||||
static int queue_index = 0;
|
||||
|
||||
static const char *state_name(AsyncState the_state)
|
||||
{
|
||||
switch (the_state) {
|
||||
case eAsyncIdle:
|
||||
return "eAsyncIdle";
|
||||
case eAsyncWaiting:
|
||||
return "eAsyncWaiting";
|
||||
case eAsyncConnecting:
|
||||
return "eAsyncConnecting";
|
||||
case eAsyncConnected:
|
||||
return "eAsyncConnected";
|
||||
}
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the command and transaction structures and their contents
|
||||
*/
|
||||
static void free_command(pAQ_Cmd myCmd)
|
||||
{
|
||||
if (myCmd) {
|
||||
pAsyncTxn myTxn = myCmd->tran;
|
||||
if (myTxn) {
|
||||
/*
|
||||
* Allow kill_private to clean it all if it wants
|
||||
*/
|
||||
if (myTxn->kill_private)
|
||||
myTxn->kill_private(myTxn);
|
||||
if (myTxn->out_buf)
|
||||
free(myTxn->out_buf);
|
||||
if (myTxn->inp_buf)
|
||||
free(myTxn->inp_buf);
|
||||
if (myTxn->proto_private)
|
||||
free(myTxn->proto_private);
|
||||
free(myTxn);
|
||||
}
|
||||
free(myCmd);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------- Local ------------------------------------
|
||||
CreateSocketAdress stolen from Tcl. Thanks to John Ousterhout
|
||||
*/
|
||||
@ -99,30 +151,175 @@ static int CreateSocketAdress(struct sockaddr_in *sockaddrPtr, /* Socket addres
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int AQ_ClearTimer(pAsyncQueue self) {
|
||||
if (self->nw_tmr) {
|
||||
NetWatchRemoveTimer(self->nw_tmr);
|
||||
self->nw_tmr = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int AQ_SetTimer(pAsyncQueue self, int msecs, pNWCallback callback, void *context) {
|
||||
int ret = 1;
|
||||
if (self->nw_tmr) {
|
||||
ret = AQ_ClearTimer(self);
|
||||
}
|
||||
NetWatchRegisterTimer(&self->nw_tmr, msecs, callback, context);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void AQ_Purge(pAsyncQueue self)
|
||||
{
|
||||
pAQ_Cmd myCmd = self->command_head;
|
||||
if (self->nw_tmr)
|
||||
AQ_ClearTimer(self);
|
||||
|
||||
gettimeofday(&self->tvLastCmd, NULL);
|
||||
while (myCmd) {
|
||||
/* Process any callback */
|
||||
if (myCmd->tran->handleResponse) {
|
||||
myCmd->tran->txn_status = ATX_TIMEOUT; /* TODO should be ATX_DISCO */
|
||||
myCmd->tran->handleResponse(myCmd->tran);
|
||||
}
|
||||
/*
|
||||
* Remove this transaction from the queue
|
||||
*/
|
||||
if (myCmd->next) {
|
||||
self->command_head = myCmd->next;
|
||||
} else
|
||||
self->command_head = self->command_tail = NULL;
|
||||
free_command(myCmd);
|
||||
myCmd = self->command_head;
|
||||
}
|
||||
}
|
||||
|
||||
static void AQ_Notify(pAsyncQueue self, int event)
|
||||
{
|
||||
pAsyncUnit unit;
|
||||
if (self->state != eAsyncConnected)
|
||||
SICSLogPrintf(eStatus, "Function: %s:%s\n", self->queue_name,
|
||||
__func__);
|
||||
for (unit = self->units; unit; unit = unit->next)
|
||||
if (unit->notify_func != NULL)
|
||||
unit->notify_func(unit->notify_cntx, event);
|
||||
}
|
||||
|
||||
static int TimedReconnect(void *cntx, int mode)
|
||||
{
|
||||
int iRet;
|
||||
char line[132];
|
||||
pAsyncQueue self = (pAsyncQueue) cntx;
|
||||
self->nw_tmr = 0;
|
||||
|
||||
if (self->state != eAsyncConnected)
|
||||
SICSLogPrintf(eStatus, "Function: %s:%s\n", self->queue_name,
|
||||
__func__);
|
||||
|
||||
AQ_Purge(self);
|
||||
|
||||
/* TODO: if self->pSock is NULL we haven't connected yet */
|
||||
|
||||
iRet = NETReconnect(self->pSock);
|
||||
/*
|
||||
* iRet can take the following values:
|
||||
* -1: The request failed
|
||||
* 0: The request is still in progress
|
||||
* +1: The request succeeded
|
||||
*/
|
||||
if (iRet <= 0) {
|
||||
if (iRet < 0) {
|
||||
snprintf(line, 132, "Failed reconnect on AsyncQueue '%s'",
|
||||
self->queue_name);
|
||||
SICSLogWrite(line, eStatus);
|
||||
/* Timer for retry */
|
||||
NetWatchSetMode(self->nw_ctx, 0);
|
||||
/* implement an exponential backoff within limits */
|
||||
self->retryTimer = 2 * self->retryTimer;
|
||||
if (self->retryTimer < 125)
|
||||
self->retryTimer = 125;
|
||||
if (self->retryTimer > 16000)
|
||||
self->retryTimer = 16000;
|
||||
AQ_SetTimer(self, self->retryTimer,
|
||||
TimedReconnect, self);
|
||||
SICSLogPrintf(eStatus, "In %s:%s: state %s => eAsyncWaiting\n",
|
||||
self->queue_name, __func__, state_name(self->state));
|
||||
self->state = eAsyncWaiting;
|
||||
} else {
|
||||
NetWatchSetMode(self->nw_ctx, nwatch_write);
|
||||
SICSLogPrintf(eStatus, "In %s:%s: state %s => eAsyncConnecting\n",
|
||||
self->queue_name, __func__, state_name(self->state));
|
||||
self->state = eAsyncConnecting;
|
||||
/* await reconnect result in MyCallback */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
NetWatchSetMode(self->nw_ctx, nwatch_read);
|
||||
SICSLogPrintf(eStatus, "In %s:%s: state %s => eAsyncConnected\n",
|
||||
self->queue_name, __func__, state_name(self->state));
|
||||
self->state = eAsyncConnected;
|
||||
snprintf(line, 132, "Reconnect on AsyncQueue '%s'", self->queue_name);
|
||||
SICSLogWrite(line, eStatus);
|
||||
AQ_Purge(self);
|
||||
AQ_Notify(self, AQU_RECONNECT);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int AQ_Reconnect(pAsyncQueue self)
|
||||
{
|
||||
int iRet;
|
||||
int sock;
|
||||
int flag = 1;
|
||||
char line[132];
|
||||
|
||||
iRet = NETReconnect(self->pSock);
|
||||
if (iRet <= 0) {
|
||||
snprintf(line, 132, "Disconnect on AsyncQueue '%s'", self->queue_name);
|
||||
SICSLogWrite(line, eStatus);
|
||||
if (self->state != eAsyncConnected)
|
||||
SICSLogPrintf(eStatus, "Function: %s:%s\n", self->queue_name,
|
||||
__func__);
|
||||
/*
|
||||
* Remove any old timer
|
||||
*/
|
||||
if (self->nw_tmr)
|
||||
AQ_ClearTimer(self);
|
||||
|
||||
if (self->state == eAsyncConnected) {
|
||||
self->state = eAsyncIdle;
|
||||
SICSLogPrintf(eStatus, "Disconnect on AsyncQueue '%s'", self->queue_name);
|
||||
AQ_Notify(self, AQU_DISCONNECT);
|
||||
AQ_Purge(self);
|
||||
}
|
||||
|
||||
iRet = NETReconnect(self->pSock);
|
||||
/*
|
||||
* iRet can take the following values:
|
||||
* -1: The request failed
|
||||
* 0: The request is still in progress
|
||||
* +1: The request succeeded
|
||||
*/
|
||||
if (iRet <= 0) {
|
||||
if (iRet < 0) {
|
||||
/* Timer for retry */
|
||||
NetWatchSetMode(self->nw_ctx, 0);
|
||||
/* implement an exponential backoff within limits */
|
||||
self->retryTimer = 125; /* initial delay */
|
||||
AQ_SetTimer(self, self->retryTimer,
|
||||
TimedReconnect, self);
|
||||
SICSLogPrintf(eStatus, "In %s:%s: state %s => eAsyncWaiting\n",
|
||||
self->queue_name, __func__, state_name(self->state));
|
||||
self->state = eAsyncWaiting;
|
||||
} else {
|
||||
NetWatchSetMode(self->nw_ctx, nwatch_write);
|
||||
SICSLogPrintf(eStatus, "In %s:%s: state %s => eAsyncConnecting\n",
|
||||
self->queue_name, __func__, state_name(self->state));
|
||||
self->state = eAsyncConnecting;
|
||||
/* await reconnect result in MyCallback */
|
||||
}
|
||||
return iRet;
|
||||
}
|
||||
NetWatchSetMode(self->nw_ctx, nwatch_read);
|
||||
SICSLogPrintf(eStatus, "In %s:%s: state %s => eAsyncConnected\n",
|
||||
self->queue_name, __func__, state_name(self->state));
|
||||
self->state = eAsyncConnected;
|
||||
snprintf(line, 132, "Reconnect on AsyncQueue '%s'", self->queue_name);
|
||||
SICSLogWrite(line, eStatus);
|
||||
AQ_Purge(self);
|
||||
AQ_Notify(self, AQU_RECONNECT);
|
||||
return 1;
|
||||
}
|
||||
@ -135,7 +332,11 @@ static int StartCommand(pAsyncQueue self)
|
||||
{
|
||||
pAQ_Cmd myCmd = self->command_head;
|
||||
mkChannel *sock = self->pSock;
|
||||
int iRet = 0;
|
||||
|
||||
if (self->state != eAsyncConnected)
|
||||
SICSLogPrintf(eStatus, "Function: %s:%s\n", self->queue_name,
|
||||
__func__);
|
||||
if (myCmd == NULL)
|
||||
return OKOK;
|
||||
|
||||
@ -143,7 +344,7 @@ static int StartCommand(pAsyncQueue self)
|
||||
* Remove any old command timeout timer
|
||||
*/
|
||||
if (self->nw_tmr)
|
||||
NetWatchRemoveTimer(self->nw_tmr);
|
||||
AQ_ClearTimer(self);
|
||||
|
||||
/*
|
||||
* Implement the inter-command delay
|
||||
@ -164,7 +365,7 @@ static int StartCommand(pAsyncQueue self)
|
||||
int delay = when.tv_sec - now.tv_sec;
|
||||
delay *= 1000;
|
||||
delay += (when.tv_usec - now.tv_usec + (1000 - 1)) / 1000;
|
||||
NetWatchRegisterTimer(&self->nw_tmr, delay, DelayedStart, self);
|
||||
AQ_SetTimer(self, delay, DelayedStart, self);
|
||||
return OKOK;
|
||||
}
|
||||
}
|
||||
@ -172,33 +373,56 @@ static int StartCommand(pAsyncQueue self)
|
||||
/*
|
||||
* Discard any input before sending command
|
||||
*/
|
||||
while (NETAvailable(sock, 0)) {
|
||||
/* TODO: handle unsolicited input */
|
||||
char reply[1];
|
||||
int iRet;
|
||||
iRet = NETRead(sock, reply, 1, 0);
|
||||
if (iRet < 0) { /* EOF */
|
||||
iRet = AQ_Reconnect(self);
|
||||
if (iRet <= 0) {
|
||||
myCmd->tran->txn_state = ATX_DISCO;
|
||||
if (myCmd->tran->handleResponse) {
|
||||
myCmd->tran->handleResponse(myCmd->tran);
|
||||
}
|
||||
PopCommand(self);
|
||||
if (NETAvailable(sock, 0)) {
|
||||
while (NETAvailable(sock, 0)) {
|
||||
/* TODO: handle unsolicited input */
|
||||
char reply[128];
|
||||
iRet = NETRead(sock, reply, 128, 0);
|
||||
if (iRet < 0) { /* EOF */
|
||||
iRet = AQ_Reconnect(self);
|
||||
return 0;
|
||||
} else if (iRet > 0) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
SICSLogTimePrintf(eError, &tv,
|
||||
"ERROR: %d unsolicited chars in AsyncQueue %s",
|
||||
iRet, self->queue_name);
|
||||
SICSLogWriteHexTime(reply, iRet, eError, &tv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
myCmd->tran->txn_status = ATX_ACTIVE;
|
||||
if (self->protocol->sendCommand) {
|
||||
iRet = self->protocol->sendCommand(self->protocol, myCmd->tran);
|
||||
} else {
|
||||
pAsyncTxn txn = myCmd->tran;
|
||||
iRet = AsyncUnitWrite(txn->unit, txn->out_buf, txn->out_len);
|
||||
if (iRet < 0)
|
||||
iRet = 0;
|
||||
else
|
||||
iRet = 1;
|
||||
}
|
||||
/*
|
||||
* Handle case of no response expected
|
||||
*/
|
||||
if (myCmd->tran->inp_len == 0 || myCmd->tran->inp_buf == NULL) {
|
||||
myCmd->tran->txn_status = ATX_COMPLETE;
|
||||
return PopCommand(self);
|
||||
}
|
||||
if (iRet > 0)
|
||||
if (myCmd->tran->txn_status == ATX_COMPLETE)
|
||||
return PopCommand(self);
|
||||
/*
|
||||
* Add a new command timeout timer
|
||||
*/
|
||||
if (myCmd->timeout > 0)
|
||||
NetWatchRegisterTimer(&self->nw_tmr, myCmd->timeout,
|
||||
AQ_SetTimer(self, myCmd->timeout,
|
||||
CommandTimeout, self);
|
||||
else
|
||||
NetWatchRegisterTimer(&self->nw_tmr, 30000, CommandTimeout, self);
|
||||
AQ_SetTimer(self, 30000, CommandTimeout, self);
|
||||
myCmd->active = 1;
|
||||
return self->protocol->sendCommand(self->protocol, myCmd->tran);
|
||||
return iRet;
|
||||
}
|
||||
|
||||
static int QueCommandHead(pAsyncQueue self, pAQ_Cmd cmd)
|
||||
@ -239,13 +463,17 @@ static int QueCommand(pAsyncQueue self, pAQ_Cmd cmd)
|
||||
self->command_tail = cmd;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int PopCommand(pAsyncQueue self)
|
||||
{
|
||||
pAQ_Cmd myCmd = self->command_head;
|
||||
if (self->nw_tmr)
|
||||
NetWatchRemoveTimer(self->nw_tmr);
|
||||
self->nw_tmr = 0;
|
||||
AQ_ClearTimer(self);
|
||||
|
||||
gettimeofday(&self->tvLastCmd, NULL);
|
||||
/* Process any callback */
|
||||
if (myCmd->tran->handleResponse)
|
||||
myCmd->tran->handleResponse(myCmd->tran);
|
||||
/*
|
||||
* If this is not the last in queue, start transmission
|
||||
*/
|
||||
@ -255,10 +483,7 @@ static int PopCommand(pAsyncQueue self)
|
||||
StartCommand(self);
|
||||
} else
|
||||
self->command_head = self->command_tail = NULL;
|
||||
free(myCmd->tran->out_buf);
|
||||
free(myCmd->tran->inp_buf);
|
||||
free(myCmd->tran);
|
||||
free(myCmd);
|
||||
free_command(myCmd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -267,6 +492,13 @@ static int CommandTimeout(void *cntx, int mode)
|
||||
pAsyncQueue self = (pAsyncQueue) cntx;
|
||||
pAQ_Cmd myCmd = self->command_head;
|
||||
self->nw_tmr = 0;
|
||||
if (self->trace) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
SICSLogTimePrintf(eLog, &tv,
|
||||
"Timeout Trace on AsyncQueue %s", self->queue_name);
|
||||
SICSLogWriteHexTime(myCmd->tran->inp_buf, myCmd->tran->inp_idx, eLog, &tv);
|
||||
}
|
||||
if (myCmd->retries > 0) {
|
||||
--myCmd->retries;
|
||||
StartCommand(self);
|
||||
@ -276,8 +508,6 @@ static int CommandTimeout(void *cntx, int mode)
|
||||
self->protocol->handleEvent(self->protocol, myCmd->tran,
|
||||
AQU_TIMEOUT);
|
||||
if (iRet == AQU_POP_CMD) {
|
||||
if (myCmd->tran->handleResponse)
|
||||
myCmd->tran->handleResponse(myCmd->tran);
|
||||
PopCommand(self); /* remove command */
|
||||
} else if (iRet == AQU_RETRY_CMD)
|
||||
StartCommand(self); /* restart command */
|
||||
@ -290,6 +520,9 @@ static int CommandTimeout(void *cntx, int mode)
|
||||
static int DelayedStart(void *cntx, int mode)
|
||||
{
|
||||
pAsyncQueue self = (pAsyncQueue) cntx;
|
||||
if (self->state != eAsyncConnected)
|
||||
SICSLogPrintf(eStatus, "Function: %s:%s\n", self->queue_name,
|
||||
__func__);
|
||||
self->nw_tmr = 0;
|
||||
StartCommand(self);
|
||||
return 1;
|
||||
@ -299,27 +532,18 @@ static int MyCallback(void *context, int mode)
|
||||
{
|
||||
pAsyncQueue self = (pAsyncQueue) context;
|
||||
|
||||
if (self->state != eAsyncConnected)
|
||||
SICSLogPrintf(eStatus, "Function: %s:%s\n", self->queue_name,
|
||||
__func__);
|
||||
if (mode & nwatch_read) {
|
||||
int iRet;
|
||||
char reply[1];
|
||||
char reply[100];
|
||||
|
||||
iRet = NETRead(self->pSock, reply, 1, 0);
|
||||
/* printf(" iRet, char = %d, %d\n", iRet, (int)reply[0]); */
|
||||
iRet = NETRead(self->pSock, reply, 100, 0);
|
||||
if (iRet < 0) { /* EOF */
|
||||
iRet = AQ_Reconnect(self);
|
||||
if (iRet <= 0) {
|
||||
/* changed to call handleResponse with a bad status code: MK
|
||||
*/
|
||||
pAQ_Cmd myCmd = self->command_head;
|
||||
if (myCmd) {
|
||||
myCmd->tran->txn_state = ATX_DISCO;
|
||||
if (myCmd->tran->handleResponse) {
|
||||
myCmd->tran->handleResponse(myCmd->tran);
|
||||
}
|
||||
PopCommand(self);
|
||||
}
|
||||
if (iRet <= 0)
|
||||
return iRet;
|
||||
}
|
||||
/* restart the command */
|
||||
StartCommand(self);
|
||||
return 1;
|
||||
@ -327,22 +551,74 @@ static int MyCallback(void *context, int mode)
|
||||
if (iRet == 0) { /* TODO: timeout or error */
|
||||
return 0;
|
||||
} else {
|
||||
int nchars = iRet;
|
||||
int i = 0;
|
||||
pAQ_Cmd myCmd = self->command_head;
|
||||
if (myCmd) {
|
||||
iRet =
|
||||
self->protocol->handleInput(self->protocol, myCmd->tran,
|
||||
reply[0]);
|
||||
if (iRet == 0 || iRet == AQU_POP_CMD) { /* end of command */
|
||||
if (myCmd->tran->handleResponse)
|
||||
myCmd->tran->handleResponse(myCmd->tran);
|
||||
PopCommand(self);
|
||||
} else if (iRet < 0) /* TODO: error */
|
||||
;
|
||||
for (i = 0; i < nchars; ++i) {
|
||||
iRet =
|
||||
self->protocol->handleInput(self->protocol, myCmd->tran,
|
||||
reply[i] & 0xFF);
|
||||
if (iRet == 0 || iRet == AQU_POP_CMD) { /* end of command */
|
||||
if (self->trace) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
SICSLogTimePrintf(eLog, &tv,
|
||||
"Input Trace on AsyncQueue %s", self->queue_name);
|
||||
SICSLogWriteHexTime(myCmd->tran->inp_buf, myCmd->tran->inp_idx, eLog, &tv);
|
||||
}
|
||||
PopCommand(self);
|
||||
break;
|
||||
} else if (iRet < 0) {
|
||||
int excess = nchars - 1 - i;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
SICSLogTimePrintf(eError, &tv,
|
||||
"ERROR: Protocol error %d in AsyncQueue %s",
|
||||
iRet, self->queue_name);
|
||||
SICSLogWriteTime("Sent:", eError, &tv);
|
||||
SICSLogWriteHexTime(myCmd->tran->out_buf, myCmd->tran->out_len, eError, &tv);
|
||||
SICSLogWriteTime("Received:", eError, &tv);
|
||||
SICSLogWriteHexTime(myCmd->tran->inp_buf, myCmd->tran->inp_idx, eError, &tv);
|
||||
SICSLogWriteTime("Processed:", eError, &tv);
|
||||
SICSLogWriteHexTime(&reply[0], i, eError, &tv);
|
||||
SICSLogWriteTime("Unprocessed:", eError, &tv);
|
||||
SICSLogWriteHexTime(&reply[i], excess, eError, &tv);
|
||||
/* TODO: error */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < nchars - 1) {
|
||||
int excess = nchars - 1 - i;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
SICSLogTimePrintf(eError, &tv,
|
||||
"ERROR: %d excess chars in AsyncQueue %s",
|
||||
excess, self->queue_name);
|
||||
SICSLogWriteHexTime(&reply[i], excess, eError, &tv);
|
||||
/* TODO: handle unsolicited */
|
||||
}
|
||||
} else {
|
||||
int excess = nchars - 1 - i;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
SICSLogTimePrintf(eError, &tv,
|
||||
"ERROR: %d unsolicited chars in AsyncQueue %s",
|
||||
excess, self->queue_name);
|
||||
SICSLogWriteHexTime(&reply[i], excess, eError, &tv);
|
||||
/* TODO: handle unsolicited input */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mode & nwatch_write) {
|
||||
char line[132];
|
||||
SICSLogPrintf(eStatus, "Writeable socket callback on AsyncQueue %s",
|
||||
self->queue_name);
|
||||
NetWatchSetMode(self->nw_ctx, nwatch_read);
|
||||
SICSLogPrintf(eStatus, "In %s:%s: state %s => eAsyncConnected\n",
|
||||
self->queue_name, __func__, state_name(self->state));
|
||||
self->state = eAsyncConnected;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -395,20 +671,43 @@ pAsyncTxn AsyncUnitPrepareTxn(pAsyncUnit unit,
|
||||
myTxn = (pAsyncTxn) malloc(sizeof(AsyncTxn));
|
||||
if (myTxn == NULL) {
|
||||
SICSLogWrite("ERROR: Out of memory in AsyncUnitPrepareTxn", eError);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
memset(myTxn, 0, sizeof(AsyncTxn));
|
||||
if (unit->queue->noreply_text) {
|
||||
if (cmd_len > unit->queue->noreply_len
|
||||
&& strncasecmp(&command[cmd_len - unit->queue->noreply_len],
|
||||
unit->queue->noreply_text, unit->queue->noreply_len) == 0) {
|
||||
rsp_len = 0;
|
||||
cmd_len -= unit->queue->noreply_len;
|
||||
}
|
||||
} else {
|
||||
if (cmd_len > 3 && strncmp(&command[cmd_len - 3], "{0}", 3) == 0) {
|
||||
rsp_len = 0;
|
||||
cmd_len -= 3;
|
||||
}
|
||||
else if (cmd_len > 11 && strncasecmp(&command[cmd_len - 11], "@@NOREPLY@@", 11) == 0) {
|
||||
rsp_len = 0;
|
||||
cmd_len -= 11;
|
||||
}
|
||||
}
|
||||
if (unit->queue->protocol->prepareTxn) {
|
||||
int iRet;
|
||||
myTxn->inp_len = rsp_len; /* allowing protocol to change it */
|
||||
iRet =
|
||||
unit->queue->protocol->prepareTxn(unit->queue->protocol, myTxn,
|
||||
command, cmd_len, rsp_len);
|
||||
if (iRet == 0) {
|
||||
free(myTxn);
|
||||
return NULL;
|
||||
}
|
||||
rsp_len = myTxn->inp_len; /* allowed protocol to change it */
|
||||
} else {
|
||||
myTxn->out_buf = (char *) malloc(cmd_len + 5);
|
||||
if (myTxn->out_buf == NULL) {
|
||||
SICSLogWrite("ERROR: Out of memory in AsyncUnitPrepareTxn", eError);
|
||||
free(myTxn);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
memcpy(myTxn->out_buf, command, cmd_len);
|
||||
myTxn->out_len = cmd_len;
|
||||
@ -423,15 +722,12 @@ pAsyncTxn AsyncUnitPrepareTxn(pAsyncUnit unit,
|
||||
if (rsp_len == 0)
|
||||
myTxn->inp_buf = NULL;
|
||||
else {
|
||||
if (myTxn->inp_buf != NULL) {
|
||||
free(myTxn->inp_buf);
|
||||
}
|
||||
myTxn->inp_buf = malloc(rsp_len + 1);
|
||||
if (myTxn->inp_buf == NULL) {
|
||||
SICSLogWrite("ERROR: Out of memory in AsyncUnitPrepareTxn", eError);
|
||||
free(myTxn->out_buf);
|
||||
free(myTxn);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
memset(myTxn->inp_buf, 0, rsp_len + 1);
|
||||
}
|
||||
@ -458,6 +754,7 @@ int AsyncUnitSendTxn(pAsyncUnit unit,
|
||||
typedef struct txn_s {
|
||||
char *transReply;
|
||||
int transWait;
|
||||
int respLen;
|
||||
} TXN, *pTXN;
|
||||
|
||||
/**
|
||||
@ -469,30 +766,33 @@ static int TransCallback(pAsyncTxn pCmd)
|
||||
int resp_len = pCmd->inp_idx;
|
||||
pTXN self = (pTXN) pCmd->cntx;
|
||||
|
||||
if (pCmd->txn_status == ATX_TIMEOUT) {
|
||||
self->respLen = resp_len;
|
||||
if (resp_len > 0) {
|
||||
memcpy(self->transReply, resp, resp_len);
|
||||
self->transReply[resp_len] = '\0';
|
||||
} else
|
||||
self->transReply[0] = '\0';
|
||||
if (pCmd->txn_status == ATX_TIMEOUT)
|
||||
self->transWait = -1;
|
||||
} else {
|
||||
memcpy(self->transReply, resp, resp_len);
|
||||
self->transReply[resp_len] = '\0';
|
||||
else
|
||||
self->transWait = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AsyncUnitTransact(pAsyncUnit unit,
|
||||
const char *command, int cmd_len,
|
||||
char *response, int rsp_len)
|
||||
char *response, int *rsp_len)
|
||||
{
|
||||
TXN txn;
|
||||
assert(unit);
|
||||
txn.transReply = response;
|
||||
txn.respLen = *rsp_len;
|
||||
txn.transWait = 1;
|
||||
AsyncUnitSendTxn(unit, command, cmd_len, TransCallback, &txn, rsp_len);
|
||||
AsyncUnitSendTxn(unit, command, cmd_len, TransCallback, &txn, *rsp_len);
|
||||
while (txn.transWait == 1)
|
||||
TaskYield(pServ->pTasker);
|
||||
*rsp_len = txn.respLen;
|
||||
if (txn.transWait < 0)
|
||||
return txn.transWait;
|
||||
return 1;
|
||||
@ -505,6 +805,13 @@ int AsyncUnitWrite(pAsyncUnit unit, void *buffer, int buflen)
|
||||
assert(unit);
|
||||
assert(unit->queue);
|
||||
if (buflen > 0) {
|
||||
if (unit->queue->trace) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
SICSLogTimePrintf(eLog, &tv,
|
||||
"Output Trace on AsyncQueue %s", unit->queue->queue_name);
|
||||
SICSLogWriteHexTime(buffer, buflen, eLog, &tv);
|
||||
}
|
||||
sock = AsyncUnitGetSocket(unit);
|
||||
iRet = NETWrite(sock, buffer, buflen);
|
||||
/* TODO handle errors */
|
||||
@ -593,24 +900,75 @@ int AsyncQueueAction(SConnection * pCon, SicsInterp * pSics,
|
||||
char line[132];
|
||||
pAsyncQueue self = (pAsyncQueue) pData;
|
||||
if (argc > 1) {
|
||||
if (strcasecmp("send", argv[1]) == 0) {
|
||||
if (strcasecmp("send", argv[1]) == 0 || strcasecmp("transact", argv[1]) == 0) {
|
||||
AsyncUnit myUnit;
|
||||
char cmd[10240];
|
||||
char rsp[10240];
|
||||
int idx = 0;
|
||||
int i, j;
|
||||
int i, j, len;
|
||||
cmd[0] = '\0';
|
||||
/* Managers only */
|
||||
if (!SCMatchRights(pCon, usMugger))
|
||||
return 0;
|
||||
for (i = 2; i < argc; ++i) {
|
||||
j = snprintf(&cmd[idx], 10240 - idx, "%s%s",
|
||||
(i > 2) ? " " : "", argv[i]);
|
||||
if (j < 0)
|
||||
if (idx >= 10240)
|
||||
break;
|
||||
idx += j;
|
||||
if (i > 2)
|
||||
cmd[idx++] = ' ';
|
||||
len = strlen(argv[i]);
|
||||
for (j = 0; j < len; ++j) {
|
||||
if (idx >= 10240)
|
||||
break;
|
||||
if (argv[i][j] == '\\') {
|
||||
++j;
|
||||
if (argv[i][j] == '\\')
|
||||
cmd[idx++] = '\\';
|
||||
else if (argv[i][j] == 'r')
|
||||
cmd[idx++] = '\r';
|
||||
else if (argv[i][j] == 'n')
|
||||
cmd[idx++] = '\n';
|
||||
else if (isdigit(argv[i][j])) {
|
||||
char *nptr = &argv[i][j];
|
||||
char *endptr;
|
||||
long k = strtol(nptr, &endptr, 0);
|
||||
cmd[idx++] = k;
|
||||
j += (endptr - nptr);
|
||||
--j; /* prepare for loop increment */
|
||||
} else
|
||||
cmd[idx++] = argv[i][j];
|
||||
} else
|
||||
cmd[idx++] = argv[i][j];
|
||||
}
|
||||
}
|
||||
cmd[idx] = '\0';
|
||||
memset(&myUnit, 0, sizeof(AsyncUnit));
|
||||
myUnit.queue = self;
|
||||
AsyncUnitTransact(&myUnit, cmd, idx, rsp, 10240);
|
||||
SCWrite(pCon, rsp, eValue);
|
||||
len = 10240;
|
||||
(void) AsyncUnitTransact(&myUnit, cmd, idx, rsp, &len);
|
||||
/* escape control characters in response */
|
||||
j = 0;
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (j >= 10230)
|
||||
break;
|
||||
if (self->translate) {
|
||||
if (rsp[i] < 32 || rsp[i] >= 127) {
|
||||
if (rsp[i] == '\r') {
|
||||
cmd[j++] = '\r';
|
||||
} else if (rsp[i] == '\n') {
|
||||
cmd[j++] = '\n';
|
||||
} else {
|
||||
j += snprintf(&cmd[j], 6, "\\0x%02x", rsp[i]);
|
||||
}
|
||||
} else if (rsp[i] == '\\') {
|
||||
cmd[j++] = '\\';
|
||||
cmd[j++] = '\\';
|
||||
} else
|
||||
cmd[j++] = rsp[i];
|
||||
} else
|
||||
cmd[j++] = rsp[i];
|
||||
}
|
||||
cmd[j++] = '\0';
|
||||
SCWrite(pCon, cmd, eValue);
|
||||
return 1;
|
||||
}
|
||||
if (strcasecmp(argv[1], "reconnect") == 0) {
|
||||
@ -627,7 +985,7 @@ int AsyncQueueAction(SConnection * pCon, SicsInterp * pSics,
|
||||
SCWrite(pCon, line, eError);
|
||||
return 0;
|
||||
} else {
|
||||
if (delay < 0 || delay > 30000) {
|
||||
if (delay < 0 || delay > 300000) {
|
||||
snprintf(line, 132, "Value out of range: %d", delay);
|
||||
SCWrite(pCon, line, eError);
|
||||
return 0;
|
||||
@ -692,6 +1050,85 @@ int AsyncQueueAction(SConnection * pCon, SicsInterp * pSics,
|
||||
}
|
||||
return OKOK;
|
||||
}
|
||||
if (strcasecmp(argv[1], "translate") == 0) {
|
||||
if (argc > 2) {
|
||||
int value;
|
||||
int iRet;
|
||||
iRet = sscanf(argv[2], "%d", &value);
|
||||
if (iRet != 1) {
|
||||
snprintf(line, 132, "Invalid argument: %s", argv[2]);
|
||||
SCWrite(pCon, line, eError);
|
||||
return 0;
|
||||
} else {
|
||||
if (value == 0) {
|
||||
self->translate = false;
|
||||
return OKOK;
|
||||
} else if (value == 1) {
|
||||
self->translate = true;
|
||||
return OKOK;
|
||||
}
|
||||
snprintf(line, 132, "Invalid argument: %s", argv[2]);
|
||||
SCWrite(pCon, line, eError);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
snprintf(line, 132, "%s.translate = %d", argv[0], self->translate);
|
||||
SCWrite(pCon, line, eStatus);
|
||||
return OKOK;
|
||||
}
|
||||
return OKOK;
|
||||
}
|
||||
if (strcasecmp(argv[1], "trace") == 0) {
|
||||
if (argc > 2) {
|
||||
int value;
|
||||
int iRet;
|
||||
iRet = sscanf(argv[2], "%d", &value);
|
||||
if (iRet != 1) {
|
||||
snprintf(line, 132, "Invalid argument: %s", argv[2]);
|
||||
SCWrite(pCon, line, eError);
|
||||
return 0;
|
||||
} else {
|
||||
if (value == 0) {
|
||||
self->trace = false;
|
||||
return OKOK;
|
||||
} else if (value == 1) {
|
||||
self->trace = true;
|
||||
return OKOK;
|
||||
}
|
||||
snprintf(line, 132, "Invalid argument: %s", argv[2]);
|
||||
SCWrite(pCon, line, eError);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
snprintf(line, 132, "%s.trace = %d", argv[0], self->trace);
|
||||
SCWrite(pCon, line, eStatus);
|
||||
return OKOK;
|
||||
}
|
||||
return OKOK;
|
||||
}
|
||||
if (strcasecmp(argv[1], "noreply") == 0) {
|
||||
if (argc > 2) {
|
||||
if (self->noreply_text)
|
||||
free(self->noreply_text);
|
||||
self->noreply_text = strdup(argv[2]);
|
||||
self->noreply_len = strlen(argv[2]);
|
||||
} else {
|
||||
SCPrintf(pCon, eValue, "%s.noreply = %s", argv[0], self->noreply_text);
|
||||
}
|
||||
return OKOK;
|
||||
}
|
||||
if (strcasecmp(argv[1], "list") == 0) {
|
||||
SCPrintf(pCon, eValue, "%s.delay = %d", argv[0], self->iDelay);
|
||||
SCPrintf(pCon, eValue, "%s.timeout = %d", argv[0], self->timeout);
|
||||
SCPrintf(pCon, eValue, "%s.retries = %d", argv[0], self->retries);
|
||||
SCPrintf(pCon, eValue, "%s.translate = %d", argv[0], self->translate);
|
||||
SCPrintf(pCon, eValue, "%s.trace = %d", argv[0], self->trace);
|
||||
if (self->noreply_text)
|
||||
SCPrintf(pCon, eValue, "%s.noreply = %s", argv[0], self->noreply_text);
|
||||
if (self->protocol && self->protocol->protocolName)
|
||||
SCPrintf(pCon, eValue, "%s.protocol = %s", argv[0], self->protocol->protocolName);
|
||||
return OKOK;
|
||||
}
|
||||
}
|
||||
snprintf(line, 132, "%s does not understand %s", argv[0], argv[1]);
|
||||
SCWrite(pCon, line, eError);
|
||||
@ -741,6 +1178,7 @@ static pAsyncQueue AQ_Create(const char *host, const char *port)
|
||||
}
|
||||
|
||||
if (self == NULL) {
|
||||
/* TODO: if channel (self->pSock) is NULL we haven't connected yet, do it later */
|
||||
if (channel == NULL)
|
||||
return NULL;
|
||||
|
||||
@ -760,6 +1198,15 @@ static pAsyncQueue AQ_Create(const char *host, const char *port)
|
||||
if (i == queue_index)
|
||||
queue_array[queue_index++] = self;
|
||||
|
||||
/* TODO: if self->pSock is NULL we haven't connected yet */
|
||||
#if 0
|
||||
if (channel == NULL) {
|
||||
/* TODO: all the rest */
|
||||
AQ_SetTimer(self, self->retryTimer, TimedReconnect,
|
||||
self);
|
||||
}
|
||||
#endif
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -769,6 +1216,7 @@ static int AQ_Init(pAsyncQueue self)
|
||||
if (self->nw_ctx == NULL)
|
||||
NetWatchRegisterCallback(&self->nw_ctx,
|
||||
self->pSock->sockid, MyCallback, self);
|
||||
NetWatchSetMode(self->nw_ctx, nwatch_write | nwatch_read);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -784,7 +1232,7 @@ static void AQ_Kill(void *pData)
|
||||
if (self->nw_ctx)
|
||||
NetWatchRemoveCallback(self->nw_ctx);
|
||||
if (self->nw_tmr)
|
||||
NetWatchRemoveTimer(self->nw_tmr);
|
||||
AQ_ClearTimer(self);
|
||||
if (self->queue_name)
|
||||
free(self->queue_name);
|
||||
NETClosePort(self->pSock);
|
||||
@ -979,3 +1427,31 @@ pAsyncUnit AsyncUnitFromQueue(pAsyncQueue queue)
|
||||
result->queue = queue;
|
||||
return result;
|
||||
}
|
||||
|
||||
void *AsyncUnitSetQueueContext(pAsyncUnit unit, void *cntx)
|
||||
{
|
||||
void *hold;
|
||||
assert(unit);
|
||||
assert(unit->queue);
|
||||
hold = unit->queue->context;
|
||||
unit->queue->context = cntx;
|
||||
return hold;
|
||||
}
|
||||
|
||||
void *AsyncUnitGetQueueContext(pAsyncUnit unit)
|
||||
{
|
||||
assert(unit);
|
||||
assert(unit->queue);
|
||||
return unit->queue->context;
|
||||
}
|
||||
|
||||
|
||||
int AsyncUnitIsQueueConnected(pAsyncUnit unit)
|
||||
{
|
||||
assert(unit);
|
||||
assert(unit->queue);
|
||||
if (unit && unit->queue)
|
||||
if (unit->queue->state == eAsyncConnected)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
31
asyncqueue.h
31
asyncqueue.h
@ -11,12 +11,6 @@
|
||||
|
||||
#include "asyncprotocol.h"
|
||||
|
||||
#define AQU_TIMEOUT -1
|
||||
#define AQU_DISCONNECT -2
|
||||
#define AQU_RECONNECT -3
|
||||
#define AQU_RETRY_CMD -4
|
||||
#define AQU_POP_CMD -5
|
||||
|
||||
typedef struct __AsyncQueue AsyncQueue, *pAsyncQueue;
|
||||
|
||||
|
||||
@ -28,7 +22,7 @@ typedef struct __AsyncQueue AsyncQueue, *pAsyncQueue;
|
||||
*/
|
||||
int AsyncUnitCreate(const char *queueName, pAsyncUnit * unit);
|
||||
/** \brief Get an AsyncUnit from a given AsyncQueue
|
||||
* \param queue The AsyncQueue fro which this AsyncUnit is valid
|
||||
* \param queue The AsyncQueue for which this AsyncUnit is valid
|
||||
* \return a new AsyncUnit or NULL on error
|
||||
*/
|
||||
pAsyncUnit AsyncUnitFromQueue(pAsyncQueue queue);
|
||||
@ -36,9 +30,13 @@ pAsyncUnit AsyncUnitFromQueue(pAsyncQueue queue);
|
||||
/** \brief create an AsyncUnit attached to an anonymous AsyncQueue.
|
||||
*
|
||||
* \param host name or address of the target host
|
||||
* \param port number or service name on the target host
|
||||
* \param port number or service name on the target host
|
||||
* \param unit pointer to the AsyncUnit created on positive return
|
||||
* \return positive if successful
|
||||
*
|
||||
* If <port> is null then <host> points to an existing queue name.
|
||||
* If a queue exists for <host>/<port>, then that queue is used.
|
||||
* If neither of the above hold, a new queue is created.
|
||||
*/
|
||||
int AsyncUnitCreateHost(const char *host,
|
||||
const char *port, pAsyncUnit * unit);
|
||||
@ -98,11 +96,12 @@ int AsyncUnitSendTxn(pAsyncUnit unit,
|
||||
* \param cmd_len length of data in command
|
||||
* \param responseHandler function to handle the response
|
||||
* \param context to be used by handler function
|
||||
* \param resp_len maximum length to be allowed for response
|
||||
* \param resp_len [in] maximum length to be allowed for response
|
||||
* [out] actual length returned
|
||||
*/
|
||||
int AsyncUnitTransact(pAsyncUnit unit,
|
||||
const char *command, int cmd_len,
|
||||
char *response, int rsp_len);
|
||||
char *response, int *rsp_len);
|
||||
|
||||
/** \brief write to the AsyncQueue file descriptor
|
||||
*
|
||||
@ -182,4 +181,16 @@ int AsyncQueueFactory(SConnection * pCon, SicsInterp * pSics,
|
||||
int AsyncQueueAction(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[]);
|
||||
|
||||
/** \brief store queue level context
|
||||
*/
|
||||
void *AsyncUnitSetQueueContext(pAsyncUnit handle, void *cntx);
|
||||
|
||||
/** \brief retrieve queue level context
|
||||
*/
|
||||
void *AsyncUnitGetQueueContext(pAsyncUnit handle);
|
||||
|
||||
/** \brief return one if queue is connected, zero otherwise
|
||||
*/
|
||||
int AsyncUnitIsQueueConnected(pAsyncUnit handle);
|
||||
|
||||
#endif /* SICSASYNCQUEUE */
|
||||
|
11
asynnet.c
11
asynnet.c
@ -397,14 +397,20 @@ void ANETprocess(void)
|
||||
{
|
||||
int i, status, count = 0, socke = 0, length;
|
||||
fd_set readMask, writeMask;
|
||||
struct timeval tmo = { 0, 20 };
|
||||
struct timeval tmo = { 0, 10000 };
|
||||
|
||||
FD_ZERO(&readMask);
|
||||
FD_ZERO(&writeMask);
|
||||
for (i = 0; i < noConnections; i++) {
|
||||
socke = connections[i].socket;
|
||||
FD_SET(socke, &readMask);
|
||||
FD_SET(socke, &writeMask);
|
||||
if (connections[i].writeBuffer != NULL) {
|
||||
GetRWBufferData(connections[i].writeBuffer, &length);
|
||||
if (length > 0)
|
||||
FD_SET(socke, &writeMask);
|
||||
else
|
||||
connections[i].lastOpenForWrite = time(NULL);
|
||||
}
|
||||
if (socke > count) {
|
||||
count = socke;
|
||||
}
|
||||
@ -575,6 +581,7 @@ void *ANETreadPtr(int handle, int *length)
|
||||
|
||||
con = findSocketDescriptor(handle);
|
||||
if (con == NULL) {
|
||||
*length = 0;
|
||||
return NULL;
|
||||
} else {
|
||||
data = GetRWBufferData(con->readBuffer, length);
|
||||
|
39
binprot.c
39
binprot.c
@ -53,18 +53,19 @@
|
||||
* modbus-crc: CRC-16-IBM, order: lo,hi
|
||||
* keller-crc: CRC-16-IBM, order: hi,lo
|
||||
* sycon-crc: sort of mod 256 checksum, byte stuffing included (no float allowed)
|
||||
* chksum-crc: simple 8bit checksum
|
||||
*/
|
||||
|
||||
typedef enum {intType, hexType, floatType,
|
||||
skipType, codeType, crcType, dumpType, errorType} BinDataType;
|
||||
// dumpType, errorType must be the last items
|
||||
|
||||
typedef enum {modbusCrc, kellerCrc, rsportCrc, syconCrc} CrcAlgorithm;
|
||||
typedef enum {modbusCrc, kellerCrc, rsportCrc, syconCrc, chksumCrc} CrcAlgorithm;
|
||||
|
||||
typedef struct {
|
||||
CrcAlgorithm crcAlgorithm;
|
||||
pDynString inp;
|
||||
char *nextFmt;
|
||||
char *nextFmt; // position of next format token
|
||||
pDynString result;
|
||||
int expectedChars;
|
||||
BinDataType type;
|
||||
@ -135,6 +136,23 @@ static int calc_crc8(char *inp, int inpLen)
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int calc_chksum(char *inp, int inpLen)
|
||||
{
|
||||
/** simple 8bit checksum
|
||||
*/
|
||||
|
||||
unsigned char crc = 0;
|
||||
unsigned char data;
|
||||
int n;
|
||||
|
||||
while (inpLen--) {
|
||||
data = *(unsigned char *) inp;
|
||||
crc += data;
|
||||
inp++;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int BinReadItem(Ascon *a) {
|
||||
@ -154,7 +172,11 @@ int BinReadItem(Ascon *a) {
|
||||
|
||||
if (strcasecmp(item, "crc") == 0) {
|
||||
p->type = crcType;
|
||||
p->expectedChars = 2;
|
||||
if (p->crcAlgorithm == chksumCrc) {
|
||||
p->expectedChars = 1;
|
||||
} else {
|
||||
p->expectedChars = 2;
|
||||
}
|
||||
p->nextFmt += valen;
|
||||
return 1;
|
||||
} else if (strncasecmp(item, "int", 3) == 0) {
|
||||
@ -281,6 +303,10 @@ int BinHandler(Ascon *a) {
|
||||
DynStringConcatChar(dyn, crc % 256);
|
||||
DynStringConcatChar(dyn, crc / 256);
|
||||
break;
|
||||
case chksumCrc:
|
||||
crc = calc_chksum(GetCharArray(dyn), l);
|
||||
DynStringConcatChar(dyn, crc % 256);
|
||||
break;
|
||||
case rsportCrc:
|
||||
crc = calc_crc8(GetCharArray(dyn), l);
|
||||
DynStringConcatChar(dyn, crc);
|
||||
@ -509,6 +535,11 @@ int BinHandler(Ascon *a) {
|
||||
DynStringConcat(p->result, "badCRC ");
|
||||
}
|
||||
break;
|
||||
case chksumCrc:
|
||||
if (calc_chksum(str, l-1) != (unsigned char)str[l-1]) {
|
||||
DynStringConcat(p->result, "badCRC ");
|
||||
}
|
||||
break;
|
||||
case kellerCrc:
|
||||
i = str[l-2];
|
||||
str[l-2] = str[l-1];
|
||||
@ -560,6 +591,8 @@ static int BinInit(Ascon * a, SConnection * con, int argc, char *argv[])
|
||||
p->crcAlgorithm = syconCrc;
|
||||
} else if (strcasecmp(argv[2], "rsport-crc") == 0) {
|
||||
p->crcAlgorithm = rsportCrc;
|
||||
} else if (strcasecmp(argv[2], "chksum-crc") == 0) {
|
||||
p->crcAlgorithm = chksumCrc;
|
||||
} else if (strcasecmp(argv[2], "modbus-crc") != 0) {
|
||||
SCPrintf(con, eError, "ERROR: unknown crc-algorithm %s", argv[2]);
|
||||
a->private = NULL;
|
||||
|
30
callback.c
30
callback.c
@ -271,6 +271,36 @@ int RemoveCallback2(pICallBack self, void *pUserData)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/*
|
||||
* Remove callback in context -
|
||||
* if the callback function matches and the user function returns zero
|
||||
*/
|
||||
int RemoveCallbackUsr(pICallBack self, SICSCallBack pFunc, int (*userfunc)(const void* pContext, const void* pUserData), void *pCtx)
|
||||
{
|
||||
pCallBackItem pItem;
|
||||
|
||||
if (!CheckPointer(self))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
pItem = self->head;
|
||||
while (pItem != NULL) {
|
||||
if (pItem->pFunc == pFunc) {
|
||||
if(userfunc(pCtx, pItem->pUserData) == 0) {
|
||||
if (debug) {
|
||||
printf("Killing callback at %p\n", self);
|
||||
}
|
||||
pItem->killFlag = 1;
|
||||
}
|
||||
}
|
||||
pItem = pItem->next;
|
||||
}
|
||||
cleanCallbackList(self);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int RemoveCallbackCon(pICallBack self, SConnection * con)
|
||||
{
|
||||
|
@ -177,7 +177,7 @@ static void KillAdapter(void *pData)
|
||||
if (self->pParName){
|
||||
free(self->pParName);
|
||||
}
|
||||
|
||||
|
||||
free(self);
|
||||
}
|
||||
|
||||
|
@ -538,7 +538,7 @@ int CommandLog(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
if (iCompact > 0)
|
||||
iIntervall = 0;
|
||||
}
|
||||
SCPrintf(pCon, eValue, "%s.compact [sec] = %d", argv[0], iCompact);
|
||||
SCPrintf(pCon, eValue, "%s.compact [sec] = %d", argv[0], (int)iCompact);
|
||||
return 1;
|
||||
} else if (strcmp(argv[1], "close") == 0) { /* close command */
|
||||
fclose(fd);
|
||||
|
@ -17,6 +17,7 @@ typedef struct __CONFVIRTMOT {
|
||||
float targetValue;
|
||||
int targetReached;
|
||||
int posCount;
|
||||
double last_report_time;
|
||||
char scriptError[512];
|
||||
int parseOK;
|
||||
}ConfigurableVirtualMotor, *pConfigurableVirtualMotor;
|
||||
|
@ -35,7 +35,11 @@
|
||||
#include "confvirtmot.h"
|
||||
#include "confvirtmot.i"
|
||||
|
||||
#define BAD_VALUE (-9999.99)
|
||||
|
||||
extern char *stptok(char *s, char *t, int len, char *brk);
|
||||
extern int CheckMotiMatch(const void* context, const void* pUserData);
|
||||
extern double DoubleTime(void);
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
An internal data structure which holds information required to control
|
||||
@ -214,6 +218,7 @@ static long ConfSetValue(void *pData, SConnection * pCon, float newValue)
|
||||
self->targetValue = newValue;
|
||||
self->targetReached = 0;
|
||||
self->posCount = 0;
|
||||
self->last_report_time = 0.0;
|
||||
|
||||
status = startMotorList(self, pCon);
|
||||
if (status != OKOK) {
|
||||
@ -303,7 +308,6 @@ static int InterestCallback(int iEvent, void *pEvent, void *pUser)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (pInfo->lastValue != pEventData->fVal) {
|
||||
pInfo->lastValue = pEventData->fVal;
|
||||
(pInfo->pCon)->conEventType = POSITION;
|
||||
@ -370,12 +374,14 @@ static int ConfCheckStatus(void *pData, SConnection * pCon)
|
||||
InvokeCallBack(self->pCall, MOTDRIVE, &event);
|
||||
}
|
||||
} else if (result == HWBusy) {
|
||||
self->posCount++;
|
||||
if (self->posCount >= 10 /*ObVal(self->ParArray,MOVECOUNT) */ ) {
|
||||
double current_time, skip_time;
|
||||
current_time = DoubleTime();
|
||||
skip_time = 0.500;
|
||||
if (self->last_report_time + skip_time <= current_time) {
|
||||
event.pName = self->name;
|
||||
event.fVal = self->pDriv->GetValue(self, pCon);
|
||||
InvokeCallBack(self->pCall, MOTDRIVE, &event);
|
||||
self->posCount = 0;
|
||||
self->last_report_time = current_time;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -431,7 +437,7 @@ static void checkMotorValues(pConfigurableVirtualMotor self,
|
||||
static float ConfGetValue(void *pData, SConnection * pCon)
|
||||
{
|
||||
pConfigurableVirtualMotor self = (pConfigurableVirtualMotor) pData;
|
||||
float currentValue = -9999.99;
|
||||
float currentValue = BAD_VALUE;
|
||||
|
||||
assert(self != NULL);
|
||||
|
||||
@ -493,6 +499,14 @@ static void KillConfigurableVirtualMotor(void *data)
|
||||
free(self->state);
|
||||
self->state = NULL;
|
||||
}
|
||||
if (self->pCall != NULL) {
|
||||
DeleteCallBackInterface(self->pCall);
|
||||
self->pCall = NULL;
|
||||
}
|
||||
if (self->pDriv != NULL) {
|
||||
free(self->pDriv);
|
||||
self->pDriv = NULL;
|
||||
}
|
||||
free(self);
|
||||
self = NULL;
|
||||
}
|
||||
@ -521,6 +535,7 @@ int MakeConfigurableVirtualMotor(SConnection * pCon, SicsInterp * pSics,
|
||||
|
||||
pNew->name = strdup(argv[1]);
|
||||
pNew->posCount = 0;
|
||||
pNew->last_report_time = 0.0;
|
||||
pNew->pDes = CreateDescriptor("ConfigurableVirtualMotor");
|
||||
pNew->pDriv = CreateDrivableInterface();
|
||||
pNew->motorList = LLDcreate(sizeof(RealMotor));
|
||||
@ -570,7 +585,6 @@ int ConfigurableVirtualMotorAction(SConnection * pCon, SicsInterp * pSics,
|
||||
pConfigurableVirtualMotor self = NULL;
|
||||
char pBueffel[512];
|
||||
float value;
|
||||
int iRet;
|
||||
long lID;
|
||||
pRegisteredInfo pRegInfo = NULL;
|
||||
|
||||
@ -685,12 +699,17 @@ int ConfigurableVirtualMotorAction(SConnection * pCon, SicsInterp * pSics,
|
||||
}
|
||||
pRegInfo->lastValue = value;
|
||||
|
||||
RemoveCallbackUsr(self->pCall, InterestCallback, CheckMotiMatch, pCon); /* only this one */
|
||||
lID = RegisterCallback(self->pCall, MOTDRIVE,
|
||||
InterestCallback, pRegInfo, KillInfo);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else if(strcmp(argv[1],"uninterest") == 0) {
|
||||
RemoveCallbackUsr(self->pCall, InterestCallback, CheckMotiMatch, pCon);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else {
|
||||
snprintf(pBueffel, 5120, "ERROR: subcommand %s to %s unknown",
|
||||
snprintf(pBueffel, sizeof(pBueffel), "ERROR: subcommand %s to %s unknown",
|
||||
argv[1], argv[0]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
|
@ -22,6 +22,7 @@ typedef struct __CONFVIRTMOT {
|
||||
float targetValue;
|
||||
int targetReached;
|
||||
int posCount;
|
||||
double last_report_time;
|
||||
char scriptError[512];
|
||||
int parseOK;
|
||||
}ConfigurableVirtualMotor, *pConfigurableVirtualMotor;
|
||||
|
326
conman.c
326
conman.c
@ -3,7 +3,7 @@
|
||||
Connection management for SICS. This is one the core files for
|
||||
SICS. Does a lot. See the descriptions with individual functions
|
||||
below.
|
||||
|
||||
|
||||
|
||||
Mark Koennecke, October 1996
|
||||
|
||||
@ -73,6 +73,16 @@
|
||||
#include "statusfile.h"
|
||||
#include "sicshipadaba.h"
|
||||
#include "protocol.h"
|
||||
#include "sicsvar.h"
|
||||
#include <json/json.h>
|
||||
|
||||
/*
|
||||
Greetings from protocol.c for SCLogWrite...
|
||||
*/
|
||||
extern struct json_object *mkJSON_Object(SConnection * pCon, char *pBuffer,
|
||||
int iOut);
|
||||
|
||||
|
||||
/*
|
||||
#define UUDEB 1
|
||||
define UUDEB , for buffer writing for checking encoding */
|
||||
@ -81,6 +91,13 @@ extern pServer pServ;
|
||||
|
||||
#include "outcode.c" /* text for OutCode */
|
||||
|
||||
int KillCapture(SConnection * pCon);
|
||||
|
||||
int LogCapture(SConnection * pCon, SicsInterp * pInter, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
int LogOutput(SConnection * pCon, SicsInterp * pInter, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
||||
/*------ Max Size of Command Stack */
|
||||
#define MAXSTACK 1024
|
||||
@ -108,6 +125,24 @@ struct SCStore {
|
||||
long macroStack;
|
||||
commandContext cc;
|
||||
};
|
||||
|
||||
/*
|
||||
* This will return the value of a SICS int variable called "sicsdebug"
|
||||
* If sicsdebug is not defined it will return 1
|
||||
* TODO Maybe define debugging levels.
|
||||
*
|
||||
* return 0=debug off, 1=debug on or sicsdebug not defined.
|
||||
*/
|
||||
int sicsdebug() {
|
||||
pSicsVariable debug;
|
||||
|
||||
debug = FindVariable(pServ->pSics, "sicsdebug");
|
||||
if (debug) {
|
||||
return debug->iVal;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/*===========================================================================*/
|
||||
static char *ConName(long ident)
|
||||
{
|
||||
@ -229,6 +264,7 @@ static SConnection *CreateConnection(SicsInterp * pSics)
|
||||
pRes->conStart = time(NULL);
|
||||
pRes->write = SCNormalWrite;
|
||||
pRes->runLevel = RUNDRIVE;
|
||||
pRes->remote = 0;
|
||||
|
||||
/* initialise context variables */
|
||||
pRes->iCmdCtr = 0;
|
||||
@ -461,6 +497,7 @@ SConnection *SCCopyConnection(SConnection * pCon)
|
||||
result->iList = -1;
|
||||
result->runLevel = pCon->runLevel;
|
||||
result->data = pCon->data;
|
||||
result->remote = pCon->remote;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -650,7 +687,7 @@ int SCPrintf(SConnection * self, int iOut, char *fmt, ...)
|
||||
va_list ap;
|
||||
char buf[256];
|
||||
char *dyn;
|
||||
int l;
|
||||
unsigned int l;
|
||||
int res;
|
||||
|
||||
va_start(ap, fmt);
|
||||
@ -779,6 +816,64 @@ static int testAndWriteSocket(SConnection * pCon, char *buffer, int iOut)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int isOK(const char *buffer)
|
||||
{
|
||||
if ((buffer[0] == 'O' && buffer[1] == 'K')
|
||||
&& (buffer[2] == '\0' || buffer[2] == '\r' || buffer[2] == '\n'))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static void testAndWriteSICSLog(SConnection * self, char *buffer, int iOut)
|
||||
{
|
||||
char tp;
|
||||
/* We don't want to log the "OK" messages */
|
||||
if (isOK(buffer))
|
||||
return;
|
||||
|
||||
if (SCinMacro(self)) {
|
||||
tp = 'M';
|
||||
if (sicsdebug())
|
||||
tp = 'D';
|
||||
} else
|
||||
tp = 'N';
|
||||
switch (iOut) {
|
||||
case eStatus:
|
||||
case eStart:
|
||||
case eFinish:
|
||||
case eEvent:
|
||||
case eHdbValue:
|
||||
case eHdbEvent:
|
||||
case eLog:
|
||||
case eLogError:
|
||||
case eError:
|
||||
case eWarning:
|
||||
/* Log it */
|
||||
SICSLogWriteCode(buffer, iOut, tp);
|
||||
return;
|
||||
case eValue:
|
||||
if (sicsdebug() || !SCinMacro(self)) {
|
||||
/* Log it */
|
||||
SICSLogWriteCode(buffer, iOut, tp);
|
||||
return;
|
||||
} else {
|
||||
/* Suppressed */
|
||||
#if 0
|
||||
tp = tolower(tp);
|
||||
SICSLogWriteCode(buffer, iOut, tp);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("Unrecognized ouput code %d in testAndWriteSICSLog: FIXME!!!\n", iOut);
|
||||
SICSLogWriteCode(buffer, iOut, tp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int SCNormalWrite(SConnection * self, char *buffer, int iOut)
|
||||
{
|
||||
@ -793,7 +888,11 @@ int SCNormalWrite(SConnection * self, char *buffer, int iOut)
|
||||
}
|
||||
|
||||
/* log it for any case */
|
||||
SICSLogWrite(buffer, iOut);
|
||||
#if 0
|
||||
SICSLogWrite(buffer, iOut);
|
||||
#else
|
||||
testAndWriteSICSLog(self, buffer, iOut);
|
||||
#endif
|
||||
|
||||
testAndWriteCommandLog(self, buffer, iOut);
|
||||
|
||||
@ -992,13 +1091,14 @@ int SCPureSockWrite(SConnection * self, char *buffer, int iOut)
|
||||
{
|
||||
char pBueffel[1024];
|
||||
char *pPtr;
|
||||
json_object *myJson = NULL;
|
||||
|
||||
/* for commandlog tail */
|
||||
if (!VerifyConnection(self)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(self->iProtocolID == 5) {
|
||||
if(self->iProtocolID == PROTACT) { /* act */
|
||||
if (strlen(buffer) + 30 > 1024) {
|
||||
pPtr = (char *) malloc((strlen(buffer) + 30) * sizeof(char));
|
||||
memset(pPtr, 0, strlen(buffer) + 20);
|
||||
@ -1010,6 +1110,12 @@ int SCPureSockWrite(SConnection * self, char *buffer, int iOut)
|
||||
if(pPtr != pBueffel){
|
||||
free(pPtr);
|
||||
}
|
||||
} else if(self->iProtocolID == PROTJSON) {
|
||||
myJson = mkJSON_Object(self,buffer,iOut);
|
||||
if(myJson != NULL){
|
||||
SCDoSockWrite(self,(char *)json_object_to_json_string(myJson));
|
||||
json_object_put(myJson);
|
||||
}
|
||||
} else {
|
||||
testAndWriteSocket(self, buffer, iOut);
|
||||
}
|
||||
@ -1023,6 +1129,7 @@ int SCLogWrite(SConnection * self, char *buffer, int iOut)
|
||||
{
|
||||
char pBueffel[1024];
|
||||
char *pPtr;
|
||||
json_object *myJson = NULL;
|
||||
|
||||
if (!VerifyConnection(self)) {
|
||||
return 0;
|
||||
@ -1031,7 +1138,7 @@ int SCLogWrite(SConnection * self, char *buffer, int iOut)
|
||||
WriteToCommandLogId(NULL, self->sockHandle, buffer);
|
||||
SetSendingConnection(NULL);
|
||||
|
||||
if(self->iProtocolID == 5) {
|
||||
if(self->iProtocolID == PROTACT) { /* act */
|
||||
if (strlen(buffer) + 30 > 1024) {
|
||||
pPtr = (char *) malloc((strlen(buffer) + 30) * sizeof(char));
|
||||
memset(pPtr, 0, strlen(buffer) + 20);
|
||||
@ -1043,7 +1150,7 @@ int SCLogWrite(SConnection * self, char *buffer, int iOut)
|
||||
if(pPtr != pBueffel){
|
||||
free(pPtr);
|
||||
}
|
||||
} else if(self->iProtocolID == 2) {
|
||||
} else if(self->iProtocolID == PROTCODE) { /* withcode */
|
||||
if (strlen(buffer) + 30 > 1024) {
|
||||
pPtr = (char *) malloc((strlen(buffer) + 30) * sizeof(char));
|
||||
memset(pPtr, 0, strlen(buffer) + 20);
|
||||
@ -1055,6 +1162,12 @@ int SCLogWrite(SConnection * self, char *buffer, int iOut)
|
||||
if(pPtr != pBueffel){
|
||||
free(pPtr);
|
||||
}
|
||||
} else if(self->iProtocolID == PROTJSON) { /* json */
|
||||
myJson = mkJSON_Object(self,buffer,iOut);
|
||||
if(myJson != NULL){
|
||||
SCDoSockWrite(self,(char *)json_object_to_json_string(myJson));
|
||||
json_object_put(myJson);
|
||||
}
|
||||
} else {
|
||||
testAndWriteSocket(self, buffer, iOut);
|
||||
}
|
||||
@ -1235,7 +1348,7 @@ int SCWriteZipped(SConnection * self, char *pName, void *pData,
|
||||
memset(outBuf, 0, 65536);
|
||||
|
||||
protocolID = GetProtocolID(self);
|
||||
if (protocolID == 5) {
|
||||
if (protocolID == PROTACT) {
|
||||
cc = SCGetContext(self);
|
||||
sprintf(outBuf, "SICSBIN ZIP %s %d %d\r\n", pName,
|
||||
compressedLength, cc.transID);
|
||||
@ -1310,7 +1423,7 @@ int SCWriteBinary(SConnection * self, char *pName, void *pData,
|
||||
memset(outBuf, 0, 65536);
|
||||
|
||||
protocolID = GetProtocolID(self);
|
||||
if (protocolID == 5) {
|
||||
if (protocolID == PROTACT) {
|
||||
cc = SCGetContext(self);
|
||||
sprintf(outBuf, "SICSBIN BIN %s %d %d\r\n", pName,
|
||||
iDataLen, cc.transID);
|
||||
@ -1416,7 +1529,7 @@ int SCWriteZippedOld(SConnection * self, char *pName, void *pData,
|
||||
memset(outBuf, 0, 65536);
|
||||
|
||||
protocolID = GetProtocolID(self);
|
||||
if (protocolID == 5) {
|
||||
if (protocolID == PROTACT) {
|
||||
cc = SCGetContext(self);
|
||||
sprintf(outBuf, "SICSBIN ZIP %s %d %d\r\n", pName,
|
||||
compressedLength, cc.transID);
|
||||
@ -1742,7 +1855,7 @@ int SCInvoke(SConnection * self, SicsInterp * pInter, char *pCommand)
|
||||
memset(pBueffel, 0, 80);
|
||||
stptok(trim(pCommand), pBueffel, 79, " ");
|
||||
self->iCmdCtr++;
|
||||
if (999999 < self->iCmdCtr) {
|
||||
if (self->iCmdCtr > 99998) {
|
||||
self->iCmdCtr = 0;
|
||||
}
|
||||
self->transID = self->iCmdCtr;
|
||||
@ -1768,6 +1881,7 @@ int SCInvoke(SConnection * self, SicsInterp * pInter, char *pCommand)
|
||||
config File Filename Logs to another file
|
||||
config output normal | withcode | ACT Sets output mode
|
||||
config listen 0 | 1 enables commandlog listen mode
|
||||
config remote sets the remote connection flag
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
int ConfigCon(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
@ -1825,7 +1939,11 @@ int ConfigCon(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else if(strcmp(argv[1],"remote") == 0) {
|
||||
pMaster->remote = 1;
|
||||
pCon->remote = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check no or args */
|
||||
if (argc < 3) {
|
||||
@ -2137,6 +2255,190 @@ int ConSicsAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hookFunc(const char *pText, OutCode eOut, void*pData)
|
||||
{
|
||||
SConnection *pCon = (SConnection *) pData;
|
||||
int text_len = strlen(pText);
|
||||
char txt[5];
|
||||
|
||||
if (!VerifyConnection(pCon)) {
|
||||
return;
|
||||
}
|
||||
if (!ANETvalidHandle(pCon->sockHandle)) {
|
||||
return;
|
||||
}
|
||||
snprintf(txt, 5, "%3s:", OutCodeToTxt(eOut));
|
||||
ANETwrite(pCon->sockHandle, txt, 4);
|
||||
ANETwrite(pCon->sockHandle, (char *)pText, text_len);
|
||||
if (pText[text_len - 1] != '\n')
|
||||
ANETwrite(pCon->sockHandle, "\n", 1);
|
||||
}
|
||||
|
||||
int KillCapture(SConnection * pCon)
|
||||
{
|
||||
RemSICSLogHook(pCon);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
the command function:
|
||||
Syntax:
|
||||
Kill kills all logging
|
||||
Log OutCode starts loggin OutCode events
|
||||
All starts logging all events
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
int LogCapture(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
SConnection * pConMaster;
|
||||
char pBueffel[512];
|
||||
int i;
|
||||
|
||||
pConMaster = SCfindMaster(pCon);
|
||||
if (pConMaster == NULL)
|
||||
return 0;
|
||||
/* check no af args */
|
||||
if (argc < 2) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "Insufficient number of arguments to %s", argv[0]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
argtolower(argc, argv);
|
||||
|
||||
/* Branch according to argv[1] */
|
||||
if (strcmp(argv[1], "kill") == 0 || strcmp(argv[1], "none") == 0) {
|
||||
SCPrintf(pCon, eLog, "getlog %s", argv[1]);
|
||||
KillCapture(pConMaster);
|
||||
return 1;
|
||||
} else if (strcmp(argv[1], "what") == 0) {
|
||||
unsigned int code_bits = 0;
|
||||
pDynString buffer;
|
||||
code_bits = (1 << iNoCodes) - 1;
|
||||
buffer = CreateDynString(100, 100);
|
||||
for (i = 0; i < iNoCodes; ++i) {
|
||||
if (code_bits & (1 << i)) {
|
||||
if (GetDynStringLength(buffer) > 0)
|
||||
DynStringConcatChar(buffer, ',');
|
||||
DynStringConcat(buffer, (char *)OutCodeToTxt(i));
|
||||
}
|
||||
}
|
||||
SCPrintf(pCon, eLog, "getlog %s", GetCharArray(buffer));
|
||||
DeleteDynString(buffer);
|
||||
return 1;
|
||||
} else if (strcmp(argv[1], "list") == 0) {
|
||||
unsigned int code_bits = 0;
|
||||
pDynString buffer;
|
||||
code_bits = GetSICSLogHook(pConMaster);
|
||||
if (code_bits == 0) {
|
||||
SCPrintf(pCon, eLog, "getlog none");
|
||||
return 1;
|
||||
}
|
||||
buffer = CreateDynString(100, 100);
|
||||
for (i = 0; i < iNoCodes; ++i) {
|
||||
if (code_bits & (1 << i)) {
|
||||
if (GetDynStringLength(buffer) > 0)
|
||||
DynStringConcatChar(buffer, ',');
|
||||
DynStringConcat(buffer, (char *)OutCodeToTxt(i));
|
||||
}
|
||||
}
|
||||
SCPrintf(pCon, eLog, "getlog %s", GetCharArray(buffer));
|
||||
DeleteDynString(buffer);
|
||||
return 1;
|
||||
} else if (strcmp(argv[1], "all") == 0) {
|
||||
SCPrintf(pCon, eLog, "getlog all");
|
||||
AddSICSLogHook(hookFunc, "all", pConMaster);
|
||||
return 1;
|
||||
} else if (argc == 2) {
|
||||
/* must be outcode, try find it */
|
||||
SCPrintf(pCon, eLog, "getlog %s", argv[1]);
|
||||
AddSICSLogHook(hookFunc, argv[1], pConMaster);
|
||||
return 1;
|
||||
} else {
|
||||
/* make it a list */
|
||||
int i;
|
||||
size_t len;
|
||||
char *pBuff;
|
||||
for (i = 1, len = 0; i < argc; ++i)
|
||||
len += strlen(argv[i]) + 1;
|
||||
if (len > sizeof(pBueffel))
|
||||
pBuff = malloc(len);
|
||||
else
|
||||
pBuff = pBueffel;
|
||||
if (pBuff == NULL) {
|
||||
SCWrite(pCon, "Out of memory in LogCapture\n", eError);
|
||||
return 1;
|
||||
}
|
||||
for (i = 1, len = 0; i < argc; ++i) {
|
||||
if (i > 1)
|
||||
pBuff[len++] = ',';
|
||||
strcpy(&pBuff[len], argv[i]);
|
||||
len += strlen(argv[i]);
|
||||
}
|
||||
SCPrintf(pCon, eLog, "getlog %s", pBuff);
|
||||
AddSICSLogHook(hookFunc, pBuff, pConMaster);
|
||||
if (pBuff != pBueffel)
|
||||
free(pBuff);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* ------------------------------------------------------------------------
|
||||
the command function:
|
||||
Syntax:
|
||||
LogOutput [OutCode] <text>
|
||||
Logs <text> with outcode OutCode default eLog
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
int LogOutput(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
char pBueffel[512];
|
||||
char *pBuff;
|
||||
int i, result, start;
|
||||
size_t len;
|
||||
OutCode outcode;
|
||||
|
||||
/* check no af args */
|
||||
if (argc < 2) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "Insufficient number of arguments to %s", argv[0]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* assume default eLog unless told otherwise */
|
||||
start = 1;
|
||||
outcode = eLog;
|
||||
if (argv[1][0] == '@') {
|
||||
result = OutCodeFromText(&argv[1][1], &outcode);
|
||||
if (result >= 0) {
|
||||
start = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* make it a string */
|
||||
for (i = start, len = 0; i < argc; ++i)
|
||||
len += strlen(argv[i]) + 1;
|
||||
if (len > sizeof(pBueffel))
|
||||
pBuff = malloc(len+10);
|
||||
else
|
||||
pBuff = pBueffel;
|
||||
if (pBuff == NULL) {
|
||||
SCWrite(pCon, "Out of memory in LogOutput\n", eError);
|
||||
return 1;
|
||||
}
|
||||
for (i = start, len = 0; i < argc; ++i) {
|
||||
if (i > start)
|
||||
pBuff[len++] = ' ';
|
||||
strcpy(&pBuff[len], argv[i]);
|
||||
len += strlen(argv[i]);
|
||||
}
|
||||
SICSLogWrite(pBuff, outcode);
|
||||
if (pBuff != pBueffel)
|
||||
free(pBuff);
|
||||
return 1;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int SCTaskFunction(void *pData)
|
||||
{
|
||||
@ -2207,7 +2509,7 @@ int SCTaskFunction(void *pData)
|
||||
pPassword = strtok(NULL, " \t\r\n");
|
||||
iRet = IsValidUser(pUser, pPassword);
|
||||
if (iRet >= 0) {
|
||||
SCWrite(self, "Login OK", eError);
|
||||
SCWrite(self, "Login OK", eLog);
|
||||
self->iLogin = 1;
|
||||
SCSetRights(self, iRet);
|
||||
pHost[0] = '\0';
|
||||
|
10
conman.h
10
conman.h
@ -71,6 +71,7 @@ typedef struct __SConnection {
|
||||
pCosta pStack; /* stack of pending commands */
|
||||
int contextStack; /* context stack: may go? */
|
||||
mkChannel *pSock; /* for temporary backwards compatability */
|
||||
int remote; /* true if this is a remote object connection */
|
||||
} SConnection;
|
||||
|
||||
#include "nserver.h"
|
||||
@ -92,7 +93,14 @@ SConnection *GetSendingConnection(void);
|
||||
/* ***************************** I/O ************************************** */
|
||||
void SCSetOutputClass(SConnection * self, int iClass);
|
||||
int SCWrite(SConnection * self, char *pBuffer, int iOut);
|
||||
int SCPrintf(SConnection * self, int iOut, char *fmt, ...);
|
||||
#if __GNUC__ > 2
|
||||
#define G_GNUC_PRINTF( format_idx, arg_idx ) \
|
||||
__attribute__((__format__ (__printf__, format_idx, arg_idx)))
|
||||
#else
|
||||
#define G_GNUC_PRINTF( format_idx, arg_idx )
|
||||
#endif
|
||||
int SCPrintf(SConnection * self, int iOut, char *fmt, ...) G_GNUC_PRINTF (3, 4);
|
||||
#undef G_GNUC_PRINTF
|
||||
int SCRead(SConnection * self, char *pBuffer, int iBufLen);
|
||||
int SCPrompt(SConnection * pCon, char *pPrompt, char *pResult, int iLen);
|
||||
int SCPromptTMO(SConnection * pCon, char *pPrompt, char *pResult, int iLen, int timeout);
|
||||
|
16
costa.c
16
costa.c
@ -108,10 +108,6 @@ int CostaTop(pCosta self, char *pCommand)
|
||||
|
||||
assert(self);
|
||||
|
||||
/* check for lock */
|
||||
if (self->iLock) {
|
||||
return 0;
|
||||
}
|
||||
/* check Size */
|
||||
if (self->iCount >= self->iMaxSize) {
|
||||
return 0;
|
||||
@ -138,11 +134,6 @@ int CostaBottom(pCosta self, char *pCommand)
|
||||
int iRet, iRes = 1;
|
||||
assert(self);
|
||||
|
||||
/* check for lock */
|
||||
if (self->iLock) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do not want 0 commands */
|
||||
if (strlen(pCommand) < 1) {
|
||||
return 1;
|
||||
@ -187,3 +178,10 @@ void CostaUnlock(pCosta self)
|
||||
{
|
||||
self->iLock = 0;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int CostaLocked(pCosta self)
|
||||
{
|
||||
return self->iLock;
|
||||
}
|
||||
|
||||
|
1
costa.h
1
costa.h
@ -25,5 +25,6 @@ int CostaPop(pCosta self, char **pPtr);
|
||||
/*----------------------------------------------------------------------*/
|
||||
void CostaLock(pCosta self);
|
||||
void CostaUnlock(pCosta self);
|
||||
int CostaLocked(pCosta self);
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*------------------------------------------------------------------------
|
||||
G E N C O U N T
|
||||
|
||||
|
||||
Some general stuff for handling a CounterDriver.
|
||||
|
||||
|
||||
@ -61,6 +61,7 @@ pCounterDriver CreateCounterDriver(char *name, char *type)
|
||||
pRes->fPreset = 1000.;
|
||||
pRes->fTime = 0.;
|
||||
pRes->iNoOfMonitors = 0;
|
||||
pRes->iControlMonitor = 0;
|
||||
pRes->iPause = 0;
|
||||
pRes->Start = NULL;
|
||||
pRes->GetStatus = NULL;
|
||||
|
15
countdriv.h
15
countdriv.h
@ -1,20 +1,20 @@
|
||||
/*---------------------------------------------------------------------------
|
||||
C O U N T E R D R I V E R
|
||||
|
||||
|
||||
|
||||
|
||||
This is the interface to a Sics-Counter driver. This means a
|
||||
single counter managing possibly several monitors in one go.
|
||||
|
||||
single counter managing possibly several monitors in one go.
|
||||
|
||||
A counter can run for a predefined time or until a predefined
|
||||
monitor count has been reached.
|
||||
|
||||
|
||||
Mark Koennecke, January 1996
|
||||
|
||||
General parameter setting added:
|
||||
Mark Koennecke, April 1999
|
||||
Mark Koennecke, April 1999
|
||||
|
||||
copyright: see implementation file.
|
||||
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
#ifndef SICSCOUNTERDRIVER
|
||||
#define SICSCOUNTERDRIVER
|
||||
@ -42,6 +42,7 @@ typedef struct __COUNTER {
|
||||
float fLastCurrent;
|
||||
float fTime;
|
||||
int iNoOfMonitors;
|
||||
int iControlMonitor;
|
||||
long lCounts[MAXCOUNT];
|
||||
int iPause;
|
||||
int iErrorCode;
|
||||
|
64
counter.c
64
counter.c
@ -551,7 +551,7 @@ static int SetCounterModeImpl(pCounter self, CounterMode eNew)
|
||||
/*-------------------------------------------------------------------------*/
|
||||
CounterMode GetCounterMode(pCounter self)
|
||||
{
|
||||
return self->getMode(self);
|
||||
return self->getMode(self);
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static CounterMode GetCounterModeImpl(pCounter self)
|
||||
@ -562,7 +562,7 @@ static CounterMode GetCounterModeImpl(pCounter self)
|
||||
/*------------------------------------------------------------------------*/
|
||||
int GetNMonitor(pCounter self)
|
||||
{
|
||||
return self->getNMonitor(self);
|
||||
return self->getNMonitor(self);
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
static int GetNMonitorImpl(pCounter self)
|
||||
@ -571,13 +571,28 @@ static int GetNMonitorImpl(pCounter self)
|
||||
return self->pDriv->iNoOfMonitors;
|
||||
}
|
||||
|
||||
int GetControlMonitor(pCounter self)
|
||||
{
|
||||
return self->pDriv->iControlMonitor;
|
||||
}
|
||||
|
||||
int SetControlMonitor(pCounter self, int channel)
|
||||
{
|
||||
int maxchan = self->pDriv->iNoOfMonitors - 1;
|
||||
if (channel < 0 || channel > maxchan) {
|
||||
return 0;
|
||||
}
|
||||
self->pDriv->iControlMonitor = channel;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef NONINTF
|
||||
extern float nintf(float f);
|
||||
#endif
|
||||
/*------------------------------------------------------------------------*/
|
||||
int SetCounterPreset(pCounter self, float fVal)
|
||||
{
|
||||
return self->setPreset(self,fVal);
|
||||
return self->setPreset(self,fVal);
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
static int SetCounterPresetImpl(pCounter self, float fVal)
|
||||
@ -603,17 +618,17 @@ static int SetCounterPresetImpl(pCounter self, float fVal)
|
||||
/*------------------------------------------------------------------------*/
|
||||
float GetCounterPreset(pCounter self)
|
||||
{
|
||||
return self->getPreset(self);
|
||||
return self->getPreset(self);
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
float GetControlValue(pCounter self)
|
||||
{
|
||||
return self->getControlValue(self);
|
||||
return self->getControlValue(self);
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
static float GetControlValueImpl(pCounter self)
|
||||
{
|
||||
return self->pDriv->fLastCurrent;
|
||||
return self->pDriv->fLastCurrent;
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
static float GetCounterPresetImpl(pCounter self)
|
||||
@ -634,7 +649,7 @@ static float GetCounterPresetImpl(pCounter self)
|
||||
/*-----------------------------------------------------------------------*/
|
||||
long GetCounts(pCounter self, SConnection * pCon)
|
||||
{
|
||||
return self->getCounts(self, pCon);
|
||||
return self->getCounts(self, pCon);
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static long GetCountsImpl(pCounter self, SConnection * pCon)
|
||||
@ -643,12 +658,12 @@ static long GetCountsImpl(pCounter self, SConnection * pCon)
|
||||
if (!self->isUpToDate) {
|
||||
self->pCountInt->TransferData(self, pCon);
|
||||
}
|
||||
return self->pDriv->lCounts[0];
|
||||
return self->pDriv->lCounts[self->pDriv->iControlMonitor];
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
long GetMonitor(pCounter self, int iNum, SConnection * pCon)
|
||||
{
|
||||
return self->getMonitor(self, iNum, pCon);
|
||||
return self->getMonitor(self, iNum, pCon);
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
static long GetMonitorImpl(pCounter self, int iNum, SConnection * pCon)
|
||||
@ -658,7 +673,7 @@ static long GetMonitorImpl(pCounter self, int iNum, SConnection * pCon)
|
||||
if (!self->isUpToDate) {
|
||||
self->pCountInt->TransferData(self, pCon);
|
||||
}
|
||||
if ((iNum < 0) || (iNum > self->pDriv->iNoOfMonitors)) {
|
||||
if ((iNum < 0) || (iNum >= self->pDriv->iNoOfMonitors)) {
|
||||
return -1L;
|
||||
} else {
|
||||
return self->pDriv->lCounts[iNum];
|
||||
@ -667,7 +682,7 @@ static long GetMonitorImpl(pCounter self, int iNum, SConnection * pCon)
|
||||
/*-----------------------------------------------------------------------*/
|
||||
void SetMonitorValue(pCounter self, int index, long value)
|
||||
{
|
||||
return self->setMonitor(self, index, value);
|
||||
return self->setMonitor(self, index, value);
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static void SetMonitorValueImpl(pCounter self, int index, long value)
|
||||
@ -681,7 +696,7 @@ static void SetMonitorValueImpl(pCounter self, int index, long value)
|
||||
/*------------------------------------------------------------------------*/
|
||||
float GetCountTime(pCounter self, SConnection * pCon)
|
||||
{
|
||||
return self->getTime(self, pCon);
|
||||
return self->getTime(self, pCon);
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
static float GetCountTimeImpl(pCounter self, SConnection * pCon)
|
||||
@ -832,6 +847,8 @@ int CountAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
{"getnmon", 0, {0, 0}},
|
||||
{"state", 0, {0, 0}},
|
||||
{"error", 0, {0, 0}},
|
||||
{"getchannel",0,{0}},
|
||||
{"setchannel",1,{FUPAINT}},
|
||||
{"countstatus", 0, {0, 0}}
|
||||
};
|
||||
char *pMode[] = {
|
||||
@ -849,8 +866,8 @@ int CountAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
argtolower(argc, argv);
|
||||
argx = &argv[1];
|
||||
iRet =
|
||||
EvaluateFuPa((pFuncTemplate) & ActionTemplate, 26, argc - 1, argx,
|
||||
&PaRes);
|
||||
EvaluateFuPa((pFuncTemplate) & ActionTemplate, 28, argc - 1, argx,
|
||||
&PaRes);
|
||||
if (iRet < 0) {
|
||||
snprintf(pBueffel, 255,"%s", PaRes.pError);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
@ -958,7 +975,7 @@ int CountAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
case 11: /* status */
|
||||
case 25:
|
||||
case 27:
|
||||
self->pCountInt->TransferData(self, pCon);
|
||||
if (GetCounterMode(self) == ePreset) {
|
||||
lVal = GetCounterPreset(self);
|
||||
@ -1144,8 +1161,8 @@ int CountAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
iRet = self->pDriv->Get(self->pDriv, PaRes.Arg[0].text,
|
||||
PaRes.Arg[1].iVal, &fVal);
|
||||
if (iRet == 1) {
|
||||
snprintf(pBueffel,255, "%s.%s %d = %f", argv[0], PaRes.Arg[0].text,
|
||||
PaRes.Arg[1].iVal, fVal);
|
||||
snprintf(pBueffel,255, "%s.%s %s = %f", argv[0], PaRes.Arg[0].text,
|
||||
PaRes.Arg[1].text, fVal);
|
||||
SCWrite(pCon, pBueffel, eValue);
|
||||
return 1;
|
||||
} else {
|
||||
@ -1172,6 +1189,19 @@ int CountAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
SCWrite(pCon, pBueffel, eValue);
|
||||
return 1;
|
||||
break;
|
||||
case 25: /* getchannel */
|
||||
snprintf(pBueffel,131,"%s.getchannel = %d", argv[0], GetControlMonitor(self));
|
||||
SCWrite(pCon,pBueffel,eValue);
|
||||
return 1;
|
||||
break;
|
||||
case 26: /* setchannel */
|
||||
if (SetControlMonitor(self, PaRes.Arg[0].iVal)) {
|
||||
return 1;
|
||||
} else {
|
||||
SCWrite(pCon,"ERROR: Invalid channel id",eError);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0); /* internal error */
|
||||
}
|
||||
|
@ -66,6 +66,8 @@ float GetControlValue(pCounter self);
|
||||
long GetCounts(pCounter self, SConnection * pCon);
|
||||
long GetMonitor(pCounter self, int iNum, SConnection * pCon);
|
||||
int GetNMonitor(pCounter self);
|
||||
int GetControlMonitor(pCounter self);
|
||||
int SetControlMonitor(pCounter self, int channel);
|
||||
void SetMonitorValue(pCounter self, int index, long value);
|
||||
float GetCountTime(pCounter self, SConnection * pCon);
|
||||
|
||||
|
27
countersec.c
27
countersec.c
@ -176,11 +176,28 @@ static int SecCtrCheckStatus(void *pData, SConnection *pCon)
|
||||
}
|
||||
ReleaseHdbValue(&v);
|
||||
|
||||
|
||||
node = GetHipadabaNode(self->pDes->parNode,"control");
|
||||
assert(node != NULL);
|
||||
GetHipadabaPar(node,&v,pCon);
|
||||
fControl = v.v.doubleValue;
|
||||
|
||||
if(self->getMode(self) == eTimer){
|
||||
node = GetHipadabaNode(self->pDes->parNode,"time");
|
||||
assert(node != NULL);
|
||||
GetHipadabaPar(node,&v,pCon);
|
||||
fControl = v.v.doubleValue;
|
||||
} else {
|
||||
node = GetHipadabaNode(self->pDes->parNode,"values");
|
||||
if(node != NULL) {
|
||||
/*
|
||||
This can be NULL if the counter is a HM. The values does not
|
||||
exist and fControl is useless
|
||||
|
||||
The 1 below is only correct for PSI where only the first
|
||||
monitor can be the control monitor. Elsewhere this must be the
|
||||
control monitor channel
|
||||
*/
|
||||
fControl = v.v.intArray[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
node = GetHipadabaNode(self->pDes->parNode,"preset");
|
||||
assert(node != NULL);
|
||||
GetHipadabaPar(node,&v,pCon);
|
||||
|
@ -785,7 +785,7 @@ int DevexecAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
|
||||
pExeList self = (pExeList) pData;
|
||||
if (argc < 2) {
|
||||
SCWrite(pCon, "ERROR: not enough argumentd to devexec command",
|
||||
SCWrite(pCon, "ERROR: not enough arguments to devexec command",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
|
3
devser.c
3
devser.c
@ -151,9 +151,6 @@ static DevAction *DevNextAction(DevSer * devser)
|
||||
}
|
||||
static void LogStart(DevSer *self)
|
||||
{
|
||||
if(self->startTime > 0){
|
||||
printf("DEVSER: there is something fucked up in LogStart. Investigate!\n");
|
||||
}
|
||||
self->startTime = DoubleTime();
|
||||
}
|
||||
static void LogResponse(DevSer *self, int error)
|
||||
|
117
diffscan.c
117
diffscan.c
@ -15,6 +15,8 @@
|
||||
#include "drive.h"
|
||||
#include "counter.h"
|
||||
|
||||
extern double DoubleTime(void);
|
||||
|
||||
#define DIFFMONITOR 0
|
||||
#define SKIP 1
|
||||
|
||||
@ -121,6 +123,57 @@ int DiffScanWrapper(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
return status;
|
||||
}
|
||||
|
||||
if (strcasecmp(argv[1], "sicsvar") == 0) {
|
||||
if (argc > 2) {
|
||||
if (strcasecmp(argv[2], "none") == 0) {
|
||||
self->sicsvar = NULL;
|
||||
return 1;
|
||||
} else {
|
||||
self->sicsvar = FindVariable(pServ->pSics, argv[2]);
|
||||
if (self->sicsvar == NULL) {
|
||||
SCPrintf(pCon, eError, "Cannot find SICS Variable: %s\n", argv[2]);
|
||||
return 0;
|
||||
}
|
||||
else if (self->sicsvar->eType != veText) {
|
||||
SCPrintf(pCon, eError, "SICS Variable must be TEXT not %s\n",
|
||||
self->sicsvar->eType == veInt ? "INT" :
|
||||
self->sicsvar->eType == veFloat ? "FLOAT" : "unknown");
|
||||
self->sicsvar = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
SCPrintf(pCon, eValue, "sicsvar = %s\n", self->sicsvar ? self->sicsvar->name : "none");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (strcasecmp(argv[1], "hdbnode") == 0) {
|
||||
if (argc > 2) {
|
||||
if (strcasecmp(argv[2], "none") == 0) {
|
||||
self->hdbnode = NULL;
|
||||
return 1;
|
||||
} else {
|
||||
self->hdbnode = FindHdbNode(NULL, argv[2], pCon);
|
||||
if (self->hdbnode == NULL) {
|
||||
SCPrintf(pCon, eError, "Cannot find HDB Node: %s\n", argv[2]);
|
||||
return 0;
|
||||
}
|
||||
else if (self->hdbnode->value.dataType != HIPTEXT) {
|
||||
SCPrintf(pCon, eError, "HDB Node %s must be TEXT\n", argv[2]);
|
||||
self->hdbnode = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
char *path = NULL;
|
||||
if (self->hdbnode != NULL)
|
||||
path = GetHipadabaPath(self->hdbnode);
|
||||
SCPrintf(pCon, eValue, "hdbnode = %s\n", path ? path : "none");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if we end here we are treating variables
|
||||
*/
|
||||
@ -180,6 +233,7 @@ static int StartDiffScan(pDiffScan self, pScanData pScan,
|
||||
self->scaleMonitor = (int) ObVal(self->parArray, DIFFMONITOR);
|
||||
self->normalizationScale = -1;
|
||||
pScan->iCounts = 0;
|
||||
pScan->iNP = 0;
|
||||
|
||||
/*
|
||||
get variable
|
||||
@ -190,6 +244,7 @@ static int StartDiffScan(pDiffScan self, pScanData pScan,
|
||||
SCWrite(pCon, "ERROR: cannot access scan variable", eError);
|
||||
return 0;
|
||||
}
|
||||
InitScanVar(pVar);
|
||||
|
||||
/*
|
||||
drive to start position
|
||||
@ -250,6 +305,9 @@ static float normalizeEntry(pCountEntry pCount, pCountEntry last,
|
||||
pCount->Monitors[i] =
|
||||
(pCount->Monitors[i] - last->Monitors[i]) * fScale;
|
||||
}
|
||||
fScale = pCount->fTime - last->fTime;
|
||||
if (fScale > 0)
|
||||
value /= fScale;
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -271,12 +329,26 @@ static int DiffScanTask(void *pData)
|
||||
char pBueffel[255];
|
||||
long rawCount, rawMon;
|
||||
CountEntry rawCopy;
|
||||
double now;
|
||||
|
||||
pDiffScan self = (pDiffScan) pData;
|
||||
|
||||
/*
|
||||
manage skip
|
||||
*/
|
||||
#if 1
|
||||
now = DoubleTime();
|
||||
if (self->skip > 0) {
|
||||
if (now - self->last_report_time < 0.001 * self->skip) {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (now - self->last_report_time < 0.1) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
self->last_report_time = now;
|
||||
#else
|
||||
if (self->skip > 0) {
|
||||
if (self->skipCount > self->skip) {
|
||||
self->skipCount = 0;
|
||||
@ -285,6 +357,7 @@ static int DiffScanTask(void *pData)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
read motor status
|
||||
@ -303,7 +376,7 @@ static int DiffScanTask(void *pData)
|
||||
status = GetDrivablePosition(pVar->pObject, self->scanObject->pCon,
|
||||
&fPos);
|
||||
if (status == 0) {
|
||||
ReleaseCountLock(pCount->pCountInt);
|
||||
ReleaseCountLock(pCount->pCountInt);
|
||||
return finish;
|
||||
}
|
||||
AppendScanVar(pVar, fPos);
|
||||
@ -323,21 +396,21 @@ static int DiffScanTask(void *pData)
|
||||
rawCount = data->lCount;
|
||||
rawMon = data->Monitors[self->scaleMonitor - 1];
|
||||
if(rawMon > 100){
|
||||
self->normalizationScale = rawMon;
|
||||
traceSys("diffscan","START:normalizing on %d, scale monitor is %d",
|
||||
self->normalizationScale, self->scaleMonitor);
|
||||
self->normalizationScale = rawMon;
|
||||
traceSys("diffscan","START:normalizing on %d, scale monitor is %d",
|
||||
self->normalizationScale, self->scaleMonitor);
|
||||
} else {
|
||||
traceSys("diffscan","START:normalization count %d, on scale monitor is %d and is to low",
|
||||
rawMon, self->scaleMonitor);
|
||||
SCWrite(self->scanObject->pCon,"WARNING: Skipping first point because of low count rate", eWarning);
|
||||
return finish;
|
||||
traceSys("diffscan","START:normalization count %ld, on scale monitor is %d and is to low",
|
||||
rawMon, self->scaleMonitor);
|
||||
SCWrite(self->scanObject->pCon,"WARNING: Skipping first point because of low count rate", eWarning);
|
||||
return finish;
|
||||
}
|
||||
} else {
|
||||
if (data->Monitors[self->scaleMonitor - 1] -
|
||||
self->last.Monitors[self->scaleMonitor - 1] < 5) {
|
||||
SCWrite(self->scanObject->pCon, "WARNING: low count rate", eLog);
|
||||
traceSys("diffscan","RUN:low monitor difference from %d to %d",data->Monitors[self->scaleMonitor-1],
|
||||
self->last.Monitors[self->scaleMonitor -1]);
|
||||
traceSys("diffscan","RUN:low monitor difference from %ld to %ld",data->Monitors[self->scaleMonitor-1],
|
||||
self->last.Monitors[self->scaleMonitor -1]);
|
||||
}
|
||||
rawCount = data->lCount;
|
||||
rawMon = data->Monitors[self->scaleMonitor - 1];
|
||||
@ -350,13 +423,26 @@ static int DiffScanTask(void *pData)
|
||||
/*
|
||||
print progress
|
||||
*/
|
||||
snprintf(pBueffel, 255, "%5d %12.4f %12.4f RAW: %10ld %10ld",
|
||||
snprintf(pBueffel, 255, "%5d %12.4f %12.4f RAW: %10ld %10ld %10.3f",
|
||||
self->scanObject->iCounts - 1,
|
||||
fPos, countValue, rawCount, rawMon);
|
||||
fPos, countValue, rawCount, rawMon, data->fTime);
|
||||
SCWrite(self->scanObject->pCon, pBueffel, eLog);
|
||||
if (self->sicsvar != NULL && self->sicsvar->eType == veText)
|
||||
VarSetText(self->sicsvar, pBueffel, usInternal);
|
||||
if (self->hdbnode != NULL && self->hdbnode->value.dataType == HIPTEXT) {
|
||||
hdbValue v;
|
||||
char error[512];
|
||||
cloneHdbValue(&self->hdbnode->value, &v);
|
||||
if (!readHdbValue(&v, pBueffel, error, 512)) {
|
||||
SCWrite(self->scanObject->pCon, error, eError);
|
||||
} else {
|
||||
UpdateHipadabaPar(self->hdbnode, v, self->scanObject->pCon);
|
||||
}
|
||||
ReleaseHdbValue(&v);
|
||||
}
|
||||
InvokeCallBack(self->scanObject->pCall, SCANPOINT, self->scanObject);
|
||||
traceSys("diffscan","RUN: pos, count, rawcount, rawmon: %f, %d, %d, %d",
|
||||
fPos, countValue, rawCount, rawMon);
|
||||
traceSys("diffscan","RUN: pos, count, rawcount, rawmon: %f, %f, %ld, %ld",
|
||||
fPos, countValue, rawCount, rawMon);
|
||||
|
||||
/*
|
||||
check for interrupt
|
||||
@ -369,7 +455,7 @@ static int DiffScanTask(void *pData)
|
||||
}
|
||||
|
||||
if(finish == 0) {
|
||||
ReleaseCountLock(pCount->pCountInt);
|
||||
ReleaseCountLock(pCount->pCountInt);
|
||||
}
|
||||
|
||||
return finish;
|
||||
@ -385,6 +471,7 @@ int RunDiffScan(pDiffScan self, pScanData pScan,
|
||||
if (StartDiffScan(self, pScan, pCon, fEnd) != 1) {
|
||||
return 0;
|
||||
}
|
||||
self->last_report_time = DoubleTime();
|
||||
InvokeCallBack(self->scanObject->pCall, SCANSTART, self->scanObject);
|
||||
|
||||
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include "obpar.h"
|
||||
#include "scan.h"
|
||||
#include "scan.i"
|
||||
#include "sicsvar.h"
|
||||
#include "hipadaba.h"
|
||||
#include "sicshipadaba.h"
|
||||
|
||||
typedef struct {
|
||||
pObjectDescriptor pDes;
|
||||
@ -22,6 +25,9 @@ typedef struct {
|
||||
int skip;
|
||||
int skipCount;
|
||||
pScanData scanObject;
|
||||
double last_report_time;
|
||||
pSicsVariable sicsvar;
|
||||
pHdb hdbnode;
|
||||
} DiffScan, *pDiffScan;
|
||||
|
||||
/*==================================================================*/
|
||||
|
@ -1,110 +0,0 @@
|
||||
\relax
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {1}Introduction}{4}}
|
||||
\@writefile{lof}{\addvspace {10\p@ }}
|
||||
\@writefile{lot}{\addvspace {10\p@ }}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {2}SICS programs, Scripts and Prerequisites}{5}}
|
||||
\@writefile{lof}{\addvspace {10\p@ }}
|
||||
\@writefile{lot}{\addvspace {10\p@ }}
|
||||
\newlabel{f0}{{2}{5}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {2.1}Hardware}{5}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {2.2}Server programs}{5}}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {3}General SICS Setup}{7}}
|
||||
\@writefile{lof}{\addvspace {10\p@ }}
|
||||
\@writefile{lot}{\addvspace {10\p@ }}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {3.1}System Control}{8}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {3.2}Moving SICS}{9}}
|
||||
\newlabel{f2}{{3.2}{9}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.1} Moving the SICS Server to a new Computer}{9}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.2}Exchanging the Serial Port Server}{9}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.2.3}Exchanging the Histogram Memory}{10}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {3.3}SICS Trouble Shooting }{10}}
|
||||
\newlabel{f3}{{3.3}{10}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.3.1}Check Server Status}{10}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.3.2}Inspecting Log Files}{10}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.3.3}Restarting SICS}{11}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.3.4}Restart Everything}{11}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.3.5}Starting SICS Manually}{11}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.3.6}Test the SerPortServer Program}{11}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.3.7}Trouble with Environment Devices}{12}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {3.3.8} HELP debugging!!!!}{12}}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {4}The SICS Initialization File}{13}}
|
||||
\@writefile{lof}{\addvspace {10\p@ }}
|
||||
\@writefile{lot}{\addvspace {10\p@ }}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {4.1}Overview of SICS Initialization}{13}}
|
||||
\newlabel{f4}{{4.1}{13}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {4.2}SICS Options and Users}{14}}
|
||||
\newlabel{f5}{{4.2}{14}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {4.3}SICS Variables }{15}}
|
||||
\newlabel{f6}{{4.3}{15}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {4.4}SICS Hardware Configuration}{16}}
|
||||
\newlabel{f7}{{4.4}{16}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.4.1}Bus Access}{16}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{Direct Access to RS232 Controllers or TCP/IP Controllers.}{16}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{Accessing Serial Ports (Old System)}{17}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{GPIB Controller Access}{19}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.4.2}Controllers}{20}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{ECB Controllers}{20}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{Siematic SPS Controllers}{21}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{General Controller Object and Choppers}{22}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.4.3} Motors}{23}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.4.4}Counting Devices}{24}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{Histogram Memory}{25}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.4.5}Velocity Selectors}{26}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {4.5}Initialization of General Commands}{27}}
|
||||
\newlabel{f10}{{4.5}{27}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.5.1}Monochromators}{28}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.5.2}Reoccuring Tasks}{28}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.5.3}The SICS Online Help System}{29}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.5.4}Aliases in SICS}{29}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{Object Aliases}{29}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{Runtime Aliases}{29}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{Command Aliases}{30}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.5.5}The AntiCollision Module}{30}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {4.6}The Internal Scan Commands}{31}}
|
||||
\newlabel{f11}{{4.6}{31}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.6.1}Scan Concepts}{31}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.6.2}User Definable Scan Functions}{34}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.6.3}User Defined Scans(Old Style)}{35}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.6.4}The Scan Command Header Description File}{35}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.6.5}Differential Scans}{36}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.6.6}Peak Analysis}{37}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.6.7}Common Scan Scripts}{37}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {4.7}Scripting NeXus Files}{37}}
|
||||
\newlabel{f12}{{4.7}{37}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.7.1}Usage}{38}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{File Opening and Closing}{38}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{Writing Things}{38}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {4.8}Automatic Updating of NeXus Files}{39}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.8.1}Prerequisites for Using the Automatic Update Manager}{39}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.8.2}Installing Automatic Update}{40}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.8.3}Configuring Automatic Update}{40}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {4.9}Instrument Specific SICS Initializations}{40}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.9.1}Initialization for Four Circle Diffractometers}{40}}
|
||||
\newlabel{f13}{{4.9.1}{40}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.9.2}Triple Axis Spectrometer Specific Commands}{42}}
|
||||
\newlabel{f14}{{4.9.2}{42}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.9.3}Special Commands for the Reflectometer (AMOR)}{42}}
|
||||
\newlabel{f15}{{4.9.3}{42}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{AMOR Status Display Commands}{43}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.9.4}SANS Special Commands}{44}}
|
||||
\newlabel{f16}{{4.9.4}{44}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {4.9.5}Special FOCUS Initializations}{45}}
|
||||
\newlabel{f17}{{4.9.5}{45}}
|
||||
\@writefile{toc}{\contentsline {subsubsection}{Special Internal FOCUS Support Commands}{45}}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {5}Programming SICS Macros}{46}}
|
||||
\@writefile{lof}{\addvspace {10\p@ }}
|
||||
\@writefile{lot}{\addvspace {10\p@ }}
|
||||
\newlabel{f18}{{5}{46}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {5.1}Input/Output}{46}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {5.2}Error Handling}{47}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {5.3}Interacting with SICS within a Script}{47}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {5.4}SICS Interfaces in Tcl}{47}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.1}The Object Interface}{47}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {5.4.2}Overriding the Drivable Interface with Tcl}{48}}
|
||||
\@writefile{toc}{\contentsline {chapter}{\numberline {6}The McStas SICS Interface}{49}}
|
||||
\@writefile{lof}{\addvspace {10\p@ }}
|
||||
\@writefile{lot}{\addvspace {10\p@ }}
|
||||
\newlabel{f8}{{6}{49}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {6.1}McStas Requirements and SICS Requirements}{50}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {6.2}The McStas Reader}{50}}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {6.3}The McStas Controller}{51}}
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
\relax
|
@ -226,7 +226,7 @@ A valid SICS object structure has to look like this:
|
||||
Please note that the first item in the data structure MUST be a
|
||||
pointer to an SICS object descriptor. Add your own stuff below
|
||||
that. If you do not adhere to this requirement, SICS will dump core on
|
||||
you rather sooner then later.
|
||||
you rather sooner than later.
|
||||
|
||||
|
||||
SICS needs this object descriptor for its own internal purposes. The
|
||||
@ -566,7 +566,7 @@ This code also shows the necessary error checking. It also shows how
|
||||
to check for possible interrupts after such an operation. It is very
|
||||
advisable to do this because the user may have interrupted the
|
||||
process. And she might not be all to happy if the new command just
|
||||
continues with the next step rather then aborting the process.
|
||||
continues with the next step rather than aborting the process.
|
||||
|
||||
|
||||
\section{SICS Interfaces}\label{interface}\label{inter}
|
||||
|
@ -8,7 +8,7 @@ subdivided into a driver and the logical object.
|
||||
There is a problem here. There are some data fields and functions
|
||||
which must be present for any motor driver. Then there are fields
|
||||
which are specific just to a special implementation of a mot
|
||||
driver. There are several ways to deal with this. The way choosen for
|
||||
driver. There are several ways to deal with this. The way chosen for
|
||||
the motor driver is a kind of overlay. The first few fields of a valid
|
||||
motor driver structure MUST be specified in the same order as given
|
||||
below. A special motor driver can add additional fields at the end of
|
||||
@ -122,12 +122,12 @@ creates a simulation motor driver.
|
||||
\end{description}
|
||||
|
||||
\subsubsection{The Motor Logical Object}
|
||||
The motor object represents the motor to SICS. One of its responsabilities
|
||||
The motor object represents the motor to SICS. One of its responsibilities
|
||||
is to drive motor operations and error checking. The scheme
|
||||
implemented is that the motor object tries to bring the motor to its
|
||||
position at least three times before a failure is recorded. Also the
|
||||
motor object keeps track of a count of failed operations. If this
|
||||
count gets to high an interrupt is issued to stop the instrument. This
|
||||
count gets too high an interrupt is issued to stop the instrument. This
|
||||
was put in after Druechal tried to drive over a slab of concrete for a
|
||||
whole night and subsequently broke a clutch.
|
||||
Motors are represented by the
|
||||
@ -164,7 +164,7 @@ object.
|
||||
Much of the action of the motor is hidden in the implementation of the
|
||||
drivable interface to the motor. Additionally the functions as given below
|
||||
are defined. All functions take a pointer to the motor object data structure
|
||||
as a parameter. They retun 0 on success or 1 on failure while not stated
|
||||
as a parameter. They return 0 on success or 1 on failure while not stated
|
||||
otherwise.
|
||||
\begin{description}
|
||||
\item[int MotorGetPar(pMotor self, char *name, float *fVal)] retrieves the
|
||||
|
@ -1,47 +1,47 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>HRPT motor list</title>
|
||||
</head>
|
||||
<body>
|
||||
<H2>HRPT motor list</H2>
|
||||
<P>
|
||||
<DL>
|
||||
<DT>CEX1
|
||||
<DD>inner collimator drum
|
||||
<DT>CEX2
|
||||
<DD>outer collimator drum
|
||||
<DT>MOMU, A1
|
||||
<DD>omega rotation of upper monochromator crystal.
|
||||
<DT>MTVU, A12
|
||||
<DD>translation vertical to the upper crystal.
|
||||
<DT>MTPU, A13
|
||||
<DD>translation paralell to the upper crystal
|
||||
<DT>MGVU, A14
|
||||
<DD>tilt goniometer vertical to upper crystal.
|
||||
<DT>MGPU, A15
|
||||
<DD>tilt goniometer paralell to upper crystal.
|
||||
<DT>MCVU, A16
|
||||
<dd>vertical curvature of upper crystal.
|
||||
<DT>MOML, B1
|
||||
<DD>omega rotation of lower monochromator crystal.
|
||||
<DT>MTVL, A22
|
||||
<DD>translation vertical to the lower crystal.
|
||||
<DT>MTPL, A23
|
||||
<DD>translation paralell to the lower crystal
|
||||
<DT>MGVL, A24
|
||||
<DD>tilt goniometer vertical to lower crystal.
|
||||
<DT>MGPL, A25
|
||||
<DD>tilt goniometer paralell to lower crystal.
|
||||
<DT>MCVL, A26
|
||||
<dd>vertical curvature of lower crystal.
|
||||
<dT>MEXZ, A37
|
||||
<DD>lift
|
||||
<DT>Table, A3
|
||||
<DD>Sample rotation.
|
||||
<DT>TwoThetaD, A4
|
||||
<DD>Two Theta detector.
|
||||
</DL>
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
<html>
|
||||
<head>
|
||||
<title>HRPT motor list</title>
|
||||
</head>
|
||||
<body>
|
||||
<H2>HRPT motor list</H2>
|
||||
<P>
|
||||
<DL>
|
||||
<DT>CEX1
|
||||
<DD>inner collimator drum
|
||||
<DT>CEX2
|
||||
<DD>outer collimator drum
|
||||
<DT>MOMU, A1
|
||||
<DD>omega rotation of upper monochromator crystal.
|
||||
<DT>MTVU, A12
|
||||
<DD>translation vertical to the upper crystal.
|
||||
<DT>MTPU, A13
|
||||
<DD>translation paralell to the upper crystal
|
||||
<DT>MGVU, A14
|
||||
<DD>tilt goniometer vertical to upper crystal.
|
||||
<DT>MGPU, A15
|
||||
<DD>tilt goniometer paralell to upper crystal.
|
||||
<DT>MCVU, A16
|
||||
<dd>vertical curvature of upper crystal.
|
||||
<DT>MOML, B1
|
||||
<DD>omega rotation of lower monochromator crystal.
|
||||
<DT>MTVL, A22
|
||||
<DD>translation vertical to the lower crystal.
|
||||
<DT>MTPL, A23
|
||||
<DD>translation paralell to the lower crystal
|
||||
<DT>MGVL, A24
|
||||
<DD>tilt goniometer vertical to lower crystal.
|
||||
<DT>MGPL, A25
|
||||
<DD>tilt goniometer paralell to lower crystal.
|
||||
<DT>MCVL, A26
|
||||
<dd>vertical curvature of lower crystal.
|
||||
<dT>MEXZ, A37
|
||||
<DD>lift
|
||||
<DT>Table, A3
|
||||
<DD>Sample rotation.
|
||||
<DT>TwoThetaD, A4
|
||||
<DD>Two Theta detector.
|
||||
</DL>
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
14
drive.c
14
drive.c
@ -1,7 +1,7 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
Implementation file for the drive command
|
||||
|
||||
|
||||
This version as Test for Device Executor.
|
||||
|
||||
Mark Koennecke, December 1996
|
||||
@ -39,6 +39,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "fortify.h"
|
||||
#include "sics.h"
|
||||
#include "drive.h"
|
||||
@ -66,7 +67,7 @@ int Drive(SConnection * pCon, SicsInterp * pInter, char *name, float fNew)
|
||||
|
||||
/* check if user is allowed to drive */
|
||||
if (!SCMatchRights(pCon, usUser)) {
|
||||
snprintf(pBueffel, 511, "Insuficient Privilege to drive %s", name);
|
||||
snprintf(pBueffel, 511, "Insufficient Privilege to drive %s", name);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
@ -301,7 +302,7 @@ int DriveWrapper(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* interprete arguments as pairs name value and try to start */
|
||||
/* interpret arguments as pairs (name, value) and check */
|
||||
for (i = 1; i < argc; i += 2) {
|
||||
if (argv[i + 1] == NULL) {
|
||||
snprintf(pBueffel, 511, "ERROR: no value found for driving %s", argv[i]);
|
||||
@ -311,7 +312,12 @@ int DriveWrapper(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
iRet = Tcl_GetDouble(tcl_interp, argv[i + 1], &dTarget);
|
||||
if (iRet == TCL_ERROR) {
|
||||
SCWrite(pCon, Tcl_GetStringResult(tcl_interp), eError);
|
||||
StopExe(GetExecutor(), "ALL");
|
||||
return 0;
|
||||
} else if (!isfinite(dTarget)) {
|
||||
snprintf(pBueffel, 511,
|
||||
"ERROR: target %s value for %s is not a finite number",
|
||||
argv[i + 1], argv[i]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
iRet = Start2Run(pCon, pSics, argv[i], RUNDRIVE, dTarget);
|
||||
|
@ -101,6 +101,7 @@ void DeleteDynString(pDynString self)
|
||||
if (self->pBuffer)
|
||||
free(self->pBuffer);
|
||||
|
||||
self->iMAGIC = 0;
|
||||
free(self);
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,14 @@ typedef struct {
|
||||
* \return the new error message list head
|
||||
*/
|
||||
|
||||
void ErrPutMsg(ErrList *list, char *fmt, ...);
|
||||
#if __GNUC__ > 2
|
||||
#define G_GNUC_PRINTF( format_idx, arg_idx ) \
|
||||
__attribute__((__format__ (__printf__, format_idx, arg_idx)))
|
||||
#else
|
||||
#define G_GNUC_PRINTF( format_idx, arg_idx )
|
||||
#endif
|
||||
void ErrPutMsg(ErrList *list, char *fmt, ...) G_GNUC_PRINTF (2, 3);
|
||||
#undef G_GNUC_PRINTF
|
||||
|
||||
/** \brief Get the most recent error message
|
||||
* \param list the error list
|
||||
|
5
exebuf.c
5
exebuf.c
@ -178,7 +178,7 @@ static pDynString findBlockEnd(pExeBuf self)
|
||||
{
|
||||
pDynString command = NULL;
|
||||
char *buffer = NULL;
|
||||
int i;
|
||||
int i, j;
|
||||
|
||||
assert(self);
|
||||
|
||||
@ -190,7 +190,8 @@ static pDynString findBlockEnd(pExeBuf self)
|
||||
if (self->end != -1) {
|
||||
self->start = self->end + 1;
|
||||
}
|
||||
for (i = self->start; i < strlen(buffer); i++) {
|
||||
j = strlen(buffer);
|
||||
for (i = self->start; i < j; i++) {
|
||||
DynStringConcatChar(command, buffer[i]);
|
||||
if (buffer[i] == '\n') {
|
||||
self->lineno++;
|
||||
|
818
fortify.doc
818
fortify.doc
@ -1,409 +1,409 @@
|
||||
|
||||
Fortify - fortified memory allocation shell for C and C++
|
||||
---------------------------------------------------------
|
||||
written by Simon P. Bullen
|
||||
Cybergraphic
|
||||
|
||||
Release 1.0, 2/2/1995
|
||||
|
||||
|
||||
|
||||
|
||||
This software is not public domain. All material in
|
||||
this archive is <20> Copyright 1995 Simon P. Bullen. The
|
||||
software is freely distrubtable, with the condition that no
|
||||
more than a nominal fee is charged for media. Everything in
|
||||
this distrubution must be kept together, in original,
|
||||
unmodified form.
|
||||
The files may be modified for your own personal use, but
|
||||
modified files may not be distributed.
|
||||
The material is provided "as is" without warranty of any
|
||||
kind. The author accepts no responsibilty for damage caused
|
||||
by this software.
|
||||
|
||||
|
||||
|
||||
email: sbullen@ozemail.com.au
|
||||
snail: Simon P. Bullen
|
||||
PO BOX 12138
|
||||
A'Beckett St
|
||||
Melbourne 3000
|
||||
Australia
|
||||
|
||||
|
||||
|
||||
CONTENTS
|
||||
--------
|
||||
Your archive should have the following files:
|
||||
|
||||
file_id.diz
|
||||
fortify.c
|
||||
fortify.doc
|
||||
fortify.h
|
||||
read.me
|
||||
test.c
|
||||
ufortify.h
|
||||
ufortify.hpp
|
||||
zfortify.cpp
|
||||
zfortify.hpp
|
||||
ztest.cpp
|
||||
|
||||
|
||||
|
||||
|
||||
OVERVIEW
|
||||
--------
|
||||
Fortify is a descendant of a library I wrote way back in 1990 called
|
||||
SafeMem. It is a (fortified) shell for memory allocations. It works with
|
||||
the malloc/free family of functions, as well as new/delete in C++. It can
|
||||
be adapted to most memory management functions; the original version of
|
||||
SafeMem worked only with the Amiga's AllocMem/FreeMem. I haven't been
|
||||
writing much Amiga specific software lately, so the Amiga version of
|
||||
Fortify is way out of date, hence it's absense from this archive.
|
||||
|
||||
Fortify is designed to detect bad things happening, or at the very
|
||||
least encourage intermittent problems to occur all the time. It is capable
|
||||
of detecting memory leaks, writes beyond and before memory blocks, and
|
||||
breaks software that relies on the state of uninitialized memory, and
|
||||
software that uses memory after it's been freed.
|
||||
|
||||
It works by allocating extra space on each block. This includes a
|
||||
private header (which is used to keep track of Fortify's list of allocated
|
||||
memory), and two "fortification" zones or sentinals (which are used to
|
||||
detect writing outside the bound of the user's memory).
|
||||
|
||||
|
||||
|
||||
|
||||
Fortify VERSUS ZFortify
|
||||
-----------------------
|
||||
Fortify provides fortification for malloc/realloc/free, and ZFortify
|
||||
provides fortifications for new/delete. It is possible to use both
|
||||
versions in the one program, if you are mixing C and C++. Just make sure
|
||||
(as you already should be) that you never free() memory you new'd, and
|
||||
other such illegal mismatching.
|
||||
(Why _Z_ fortify? It's a long story...)
|
||||
|
||||
|
||||
|
||||
Fortify INSTALLATION (C)
|
||||
------------------------
|
||||
To use Fortify, each source file will need to #include "fortify.h". To
|
||||
enable Fortify, define the symbol FORTIFY. If FORTIFY is not defined, it
|
||||
will compile away to nothing. If you do not have stdout available, you may
|
||||
wish to set an alternate output function. See Fortify_SetOutputFunc(),
|
||||
below.
|
||||
You will also need to link in fortify.o
|
||||
|
||||
|
||||
|
||||
|
||||
ZFortify INSTALLATION (C++)
|
||||
---------------------------
|
||||
The minimum you need to do for ZFortify is to define the symbol
|
||||
ZFORTIFY, and link zfortify.o. Each source file should also include
|
||||
"zfortify.hpp", but this isn't strictly necessary. If a file doesn't
|
||||
#include "Fortify.hpp", then it's allocations will still be fortified,
|
||||
however you will not have any source-code details in any of the output
|
||||
messages (this will be the case for all libraries, etc, unless you have the
|
||||
source for the library and can recompile it with Fortify).
|
||||
If you do not have stdout available, you may wish to set an alternate
|
||||
output function, or turn on the AUTOMATIC_LOGFILE. See
|
||||
ZFortify_SetOutputFunc() and AUTOMATIC_LOGFILE, below.
|
||||
|
||||
|
||||
|
||||
|
||||
COMPILE TIME CUSTOMIZATIONS
|
||||
---------------------------
|
||||
The files "ufortify.h" and "ufortify.hpp" contain a number of #defines
|
||||
that you can use to customize Fortify's behavior.
|
||||
|
||||
|
||||
#define ZFORTIFY_PROVIDE_ARRAY_NEW
|
||||
|
||||
Some C++ compilers have a separate operator for newing arrays. If your
|
||||
compiler does, you will need to define this symbol. If you are unsure,
|
||||
dont worry about it too much, your program won't compile or link without
|
||||
the correct setting. GCC 2.6.3 and Borland C++ 4.5 both need this symbol.
|
||||
Microsoft C++ 1.5 and SAS 6.5 C++ both dont.
|
||||
|
||||
|
||||
#define FORTIFY_STORAGE
|
||||
|
||||
#define ZFORTIFY_STORAGE
|
||||
|
||||
You can use this to apply a storage type to all of Fortify's exportable
|
||||
functions. If you are putting Fortify in an export library for example,
|
||||
you may need to put __export here, or some such rubbish.
|
||||
|
||||
|
||||
#define FORTIFY_BEFORE_SIZE 32
|
||||
#define FORTIFY_BEFORE_VALUE 0xA3
|
||||
|
||||
#define FORTIFY_AFTER_SIZE 32
|
||||
#define FORTIFY_AFTER_VALUE 0xA5
|
||||
|
||||
#define ZFORTIFY_BEFORE_SIZE 32
|
||||
#define ZFORTIFY_BEFORE_VALUE 0xA3
|
||||
|
||||
#define ZFORTIFY_AFTER_SIZE 32
|
||||
#define ZFORTIFY_AFTER_VALUE 0xA5
|
||||
|
||||
These values define how much "fortification" is placed around each
|
||||
memory block you allocate. Fortify will place _BEFORE_SIZE bytes worth of
|
||||
memory right before your allocation block, and _AFTER_SIZE bytes worth
|
||||
after your allocation block, and these will be initialized to _BEFORE_VALUE
|
||||
and _AFTER_VALUE respectively. If your program then accidentally writes
|
||||
too far beyond the end of the block, for example, Fortify will be able to
|
||||
detect this (so long as you didn't happen to write in _AFTER_VALUE!).
|
||||
|
||||
If you don't want these fortifications to be allocated, specify a
|
||||
_SIZE of 0. Note that the _VALUE parameters are 8 bits.
|
||||
|
||||
|
||||
|
||||
#define FILL_ON_MALLOC
|
||||
#define FILL_ON_MALLOC_VALUE 0xA7
|
||||
|
||||
#define FILL_ON_NEW
|
||||
#define FILL_ON_NEW_VALUE 0xA7
|
||||
|
||||
Programs often rely on uninitialized memory being certain values
|
||||
(usually 0). If you define FILL_ON_NEW, all memory that you new will be
|
||||
initialized to FILL_ON_NEW_VALUE, which you should define to be some horrid
|
||||
value (definately NOT 0). This will encourage all code that relies on
|
||||
uninitialized memory to behave rather differently when Fortify is running.
|
||||
|
||||
|
||||
|
||||
#define FILL_ON_FREE
|
||||
#define FILL_ON_FREE_VALUE 0xA9
|
||||
|
||||
#define FILL_ON_DELETE
|
||||
#define FILL_ON_DELETE_VALUE 0xA9
|
||||
|
||||
Programmers often try to use memory after they've freed it, which can
|
||||
sometimes work (so long as noboby else has modified the memory before you
|
||||
look at it), but is incredibly dangerous and definately bad practice. If
|
||||
FILL_ON_DELETE is defined, all memory you free will be stomped out with
|
||||
FILL_ON_DELETE_VALUE, which ensures that any attempt to read freed memory
|
||||
will give incorrect results.
|
||||
|
||||
|
||||
|
||||
#define CHECK_ALL_MEMORY_ON_MALLOC
|
||||
#define CHECK_ALL_MEMORY_ON_FREE
|
||||
|
||||
#define CHECK_ALL_MEMORY_ON_NEW
|
||||
#define CHECK_ALL_MEMORY_ON_DELETE
|
||||
|
||||
CHECK_ALL_MEMORY_ON... means that for every single memory allocation
|
||||
or deallocation, every single block of memory will be checked. This can
|
||||
considerably slow down programs if you have a large number of blocks
|
||||
allocated. You would normally only need to turn this on if you are trying
|
||||
to pinpoint where a corruption was occurring.
|
||||
A block of memory is always checked when it is freed, so if
|
||||
CHECK_ALL... isn't turned on, corruptions will still be detected
|
||||
eventually.
|
||||
You can also force Fortify to check all memory with a call to
|
||||
Fortify_CheckAllMemory(). If you have a memory corruption you can't find,
|
||||
sprinkling these through the suspect code will help narrow it down.
|
||||
|
||||
|
||||
|
||||
#define PARANOID_FREE
|
||||
|
||||
#define PARANOID_DELETE
|
||||
|
||||
PARANOID_... - This means that zFortify traverses the memory list to
|
||||
ensure the memory you are about to free was really allocated by it. You
|
||||
probably only need this in extreme circumstances. Not having this defined
|
||||
will still trap attempts to free memory that wasn't allocated, unless
|
||||
someone is deliberately trying to fool zFortify.
|
||||
Paranoid mode adds considerable overhead to freeing memory, especially
|
||||
if you are freeing things in the same order you allocated them (Paranoid
|
||||
mode is most efficient if you are freeing things in the reverse order they
|
||||
were allocated).
|
||||
|
||||
|
||||
|
||||
#define WARN_ON_MALLOC_FAIL
|
||||
#define WARN_ON_ZERO_MALLOC
|
||||
#define WARN_ON_FALSE_FAIL
|
||||
#define WARN_ON_UNSIGNED_LONG_OVERFLOW
|
||||
|
||||
#define WARN_ON_NEW_FAIL
|
||||
#define WARN_ON_ZERO_NEW
|
||||
|
||||
These defines enable the output of warning that aren't strictly errors,
|
||||
but can be useful to determine what lead to a program crashing.
|
||||
WARN_ON_NEW_FAIL causes a debug to be issued whenever new fails.
|
||||
WARN_ON_ZERO_NEW causes a debug to be issued whenever a new of a zero
|
||||
byte object is attempted. This is fairly unlikely in C++, and is much more
|
||||
likely when using malloc().
|
||||
WARN_ON_FALSE_FAIL causes a debug to be issued when a new is "false"
|
||||
failed. ZSee Fortify_SetNewFailRate() for more information.
|
||||
WARN_ON_UNSIGNED_LONG_OVERFLOW causes Fortify to check for breaking the
|
||||
32 bit limit. This was more of a problem in 16-bit applications where
|
||||
breaking the 16 bit limit was much more likely. The problem is that
|
||||
Fortify adds a small amount of overhead to a memory block; so in a 16-bit
|
||||
size_t environment, if you tried to allocate 64K, Fortify would make that
|
||||
block bigger than 64K and your allocation would fail due to the presence of
|
||||
Fortify. With size_t being 32 bits for all environments worth programming
|
||||
in, this problem is extremely unlikely (Unless you plan to allocate 4
|
||||
gigabytes).
|
||||
|
||||
|
||||
#define AUTOMATIC_LOG_FILE
|
||||
#define LOG_FILENAME "fortify.log"
|
||||
#define FIRST_ERROR_FUNCTION
|
||||
|
||||
If AUTOMATIC_LOG_FILE is defined (C++ version /ZFortify only), then
|
||||
Fortify will be automatically started for you, Fortify messages sent to the
|
||||
named log file, and a list of unfreed memory dumped on termination (where
|
||||
the log file will be automatically closed for you. If no Fortify was
|
||||
output, the log file will not be altered. There are timestamps in the log
|
||||
file to ensure you're reading the correct messages.
|
||||
FIRST_ERROR_FUNCTION will be called upon generation of the first
|
||||
Fortify message, so that the user can tell a Fortify report has been
|
||||
generated. Otherwise, Fortify would quietly write all this useful stuff
|
||||
out to the log file, and no-one would know to look there!
|
||||
|
||||
|
||||
|
||||
#define FORTIFY_LOCK()
|
||||
#define FORTIFY_UNLOCK()
|
||||
|
||||
#define ZFORTIFY_LOCK()
|
||||
#define ZFORTIFY_UNLOCK()
|
||||
|
||||
In a multi-threaded environment, we need to arbitrate access to the
|
||||
foritfy memory list. This is what ZFORTIFY_LOCK() and ZFORTIFY_UNLOCK()
|
||||
are used for. The calls to ZFORTIFY_LOCK() and ZFORTIFY_UNLOCK() must
|
||||
nest. If no two threads/tasks/processes will be using the same Fortify at
|
||||
the same time, then ZFORTIFY_LOCK() and ZFORTIFY_UNLOCK() can safely be
|
||||
#defined away to nothing.
|
||||
|
||||
|
||||
|
||||
|
||||
RUN TIME CONTROL
|
||||
----------------
|
||||
Fortify can also be controlled at run time with a few special
|
||||
functions, which compile away to nothing if FORTIFY isn't defined, and do
|
||||
nothing if Fortify has been disabled with Fortify_Disable(). These
|
||||
functions all apply to ZFortify as well (The ZFortify versions have a
|
||||
ZFortify_ prefix, of course).
|
||||
|
||||
Fortify_Disable() - This function provides a mechanism to disable
|
||||
Fortify without recompiling all the sourcecode. It can only be called,
|
||||
though, when there is no memory on the Fortify list. (Ideally, at the
|
||||
start of the program before any memory has been allocated). If you call
|
||||
this function when there IS memory on the Fortify list, it will issue an
|
||||
error, and Fortify will not be disabled.
|
||||
|
||||
Fortify_SetOutputFunc(Fortify_OutputFuncPtr Output) - Sets the function
|
||||
used to output all error and diagnostic messages by Fortify. The output
|
||||
function takes a single (const char *) argument, and must be able to handle
|
||||
newlines. The function returns the old pointer.
|
||||
The default output func is a printf() to stdout. Unless you are using
|
||||
AUTOMATIC_LOG_FILE, where the default is to output to the log file.
|
||||
|
||||
Fortify_SetNewFailRate(int Percent) - Fortify will make a new attempt
|
||||
"fail" this "Percent" of the time, even if the memory IS available. Useful
|
||||
to "stress-test" an application. Returns the old value. The fail rate
|
||||
defaults to 0.
|
||||
|
||||
|
||||
|
||||
DIAGNOSTIC FUNCTIONS
|
||||
--------------------
|
||||
Fortify also provides some additional diagnostic functions which can be
|
||||
used to track down memory corruption and memory leaks. If Fortify is
|
||||
disabled, these functions do nothing. If calling these functions directly
|
||||
from a debugger, remember to add the "char *file" and "unsigned long line"
|
||||
paramters to each of the calls. (The ZFortify versions have a
|
||||
ZFortify_ prefix, of course).
|
||||
|
||||
Fortify_CheckPointer(void *uptr) - Returns true if the uptr points to a
|
||||
valid piece of Fortify'd memory. The memory must be on Fortify's list, and
|
||||
it's sentinals must be in tact. If anything is wrong, an error message is
|
||||
issued (Note - if Fortify is disabled, this function always returns true).
|
||||
|
||||
Fortify_CheckAllMemory() - Checks the sentinals of all malloc'd memory.
|
||||
Returns the number of blocks that failed. (If Fortify is disabled, this
|
||||
function always returns 0).
|
||||
|
||||
Fortify_OutputAllMemory() - Outputs the entire list of currently
|
||||
allocated memory. For each block is output it's Address, Size, the
|
||||
SourceFile and Line that allocated it, and the fortify scope from within it
|
||||
was allocated. If there is no memory on the list, this function outputs
|
||||
nothing. It returns the number of blocks on the list, unless Fortify has
|
||||
been disabled, in which case it always returns 0.
|
||||
|
||||
Fortify_DumpAllMemory(scope) - Just like Fortify_OutputAllMemory,
|
||||
except all memory inside the given scope is output, and a hex dump of each
|
||||
block is included in the output.
|
||||
|
||||
Fortify_EnterScope() - enters a level of fortify scope. Returns the
|
||||
new scope level.
|
||||
|
||||
Fortify_LeaveScope() - leaves a level of fortify scope, it also prints
|
||||
a dump of all memory allocated within the scope being left. This can be
|
||||
very useful in tracking down memory leaks in a part of a program. If you
|
||||
place a EnterScope/LeaveScope pair around a set of functions that should
|
||||
have no memory allocated when it's done, Fortify will let you know if this
|
||||
isn't the case.
|
||||
|
||||
|
||||
PROBLEMS WITH THE new AND delete MACROS
|
||||
---------------------------------------
|
||||
Due to limitations of the preprocessor, getting caller sourcecode
|
||||
information isn't as easy as it is for malloc() and free(). The macro for
|
||||
"new" which adds this information onto the new call causes syntax errors if
|
||||
you try to declare a custom new operator. The actual Fortifying works
|
||||
fine, it's just the macro expansion which causes problems.
|
||||
If this happens, you will need to place #undef's and #define's around
|
||||
the offending code (sorry). Alternatively, you can not #include
|
||||
"zfortify.hpp" for the offending file. But remember that none of the
|
||||
allocation done in that file will have sourcecode information.
|
||||
|
||||
eg.
|
||||
#undef new
|
||||
void *X::operator new(size_t) { return malloc(size_t); }
|
||||
#define new Fortify_New
|
||||
|
||||
|
||||
Due to a limitation with delete, Fortify has limited information about
|
||||
where delete is being called called from, and so the the line and source
|
||||
information will often say "delete.0". If a delete is occuring from within
|
||||
another delete, Fortify will always endeavour to report the highest level
|
||||
delete as the caller.
|
||||
|
||||
It should be possible to replace the "new.0" and "delete.0" with the
|
||||
return address of the function, which would be useful when in a debugger,
|
||||
but this would be highly architecture dependant, so I leave that as an
|
||||
exercise for the students :-).
|
||||
|
||||
|
||||
|
||||
WHEN TO USE FORTIFY
|
||||
-------------------
|
||||
The simple answer to this is "All The Time". You should never be
|
||||
without Fortify when you're actually developing software. It will detect
|
||||
your bugs _as_you_write_them_, which makes them a lot easier to find. One
|
||||
programmer who recently started using Fortify when he had a very strange
|
||||
memory problem, spent at least 3 or 4 days tracking down _other_ memory
|
||||
corruption bugs that he wasn't even aware of before the program would stay
|
||||
up long enough to get to his original problem. If he'd been using Fortify
|
||||
from the beginning, this wouldn't have been a problem.
|
||||
Leave fortify enabled until the final test and release of your
|
||||
software. You probably won't want some of the slower options, such as
|
||||
CHECK_ALL_MEMORY_ON_FREE, and PARANOID_FREE. With the exception of those
|
||||
options, Fortify doesn't have a great deal of overhead. If posing a great
|
||||
problem, this overhead can be greatly reduced by cutting down on the size
|
||||
of the fortifications, and turning off the pre/post fills, but each thing
|
||||
you turn off gives fortify less information to work with in tracking your
|
||||
bugs.
|
||||
|
||||
|
||||
Fortify - fortified memory allocation shell for C and C++
|
||||
---------------------------------------------------------
|
||||
written by Simon P. Bullen
|
||||
Cybergraphic
|
||||
|
||||
Release 1.0, 2/2/1995
|
||||
|
||||
|
||||
|
||||
|
||||
This software is not public domain. All material in
|
||||
this archive is <20> Copyright 1995 Simon P. Bullen. The
|
||||
software is freely distrubtable, with the condition that no
|
||||
more than a nominal fee is charged for media. Everything in
|
||||
this distrubution must be kept together, in original,
|
||||
unmodified form.
|
||||
The files may be modified for your own personal use, but
|
||||
modified files may not be distributed.
|
||||
The material is provided "as is" without warranty of any
|
||||
kind. The author accepts no responsibilty for damage caused
|
||||
by this software.
|
||||
|
||||
|
||||
|
||||
email: sbullen@ozemail.com.au
|
||||
snail: Simon P. Bullen
|
||||
PO BOX 12138
|
||||
A'Beckett St
|
||||
Melbourne 3000
|
||||
Australia
|
||||
|
||||
|
||||
|
||||
CONTENTS
|
||||
--------
|
||||
Your archive should have the following files:
|
||||
|
||||
file_id.diz
|
||||
fortify.c
|
||||
fortify.doc
|
||||
fortify.h
|
||||
read.me
|
||||
test.c
|
||||
ufortify.h
|
||||
ufortify.hpp
|
||||
zfortify.cpp
|
||||
zfortify.hpp
|
||||
ztest.cpp
|
||||
|
||||
|
||||
|
||||
|
||||
OVERVIEW
|
||||
--------
|
||||
Fortify is a descendant of a library I wrote way back in 1990 called
|
||||
SafeMem. It is a (fortified) shell for memory allocations. It works with
|
||||
the malloc/free family of functions, as well as new/delete in C++. It can
|
||||
be adapted to most memory management functions; the original version of
|
||||
SafeMem worked only with the Amiga's AllocMem/FreeMem. I haven't been
|
||||
writing much Amiga specific software lately, so the Amiga version of
|
||||
Fortify is way out of date, hence it's absense from this archive.
|
||||
|
||||
Fortify is designed to detect bad things happening, or at the very
|
||||
least encourage intermittent problems to occur all the time. It is capable
|
||||
of detecting memory leaks, writes beyond and before memory blocks, and
|
||||
breaks software that relies on the state of uninitialized memory, and
|
||||
software that uses memory after it's been freed.
|
||||
|
||||
It works by allocating extra space on each block. This includes a
|
||||
private header (which is used to keep track of Fortify's list of allocated
|
||||
memory), and two "fortification" zones or sentinals (which are used to
|
||||
detect writing outside the bound of the user's memory).
|
||||
|
||||
|
||||
|
||||
|
||||
Fortify VERSUS ZFortify
|
||||
-----------------------
|
||||
Fortify provides fortification for malloc/realloc/free, and ZFortify
|
||||
provides fortifications for new/delete. It is possible to use both
|
||||
versions in the one program, if you are mixing C and C++. Just make sure
|
||||
(as you already should be) that you never free() memory you new'd, and
|
||||
other such illegal mismatching.
|
||||
(Why _Z_ fortify? It's a long story...)
|
||||
|
||||
|
||||
|
||||
Fortify INSTALLATION (C)
|
||||
------------------------
|
||||
To use Fortify, each source file will need to #include "fortify.h". To
|
||||
enable Fortify, define the symbol FORTIFY. If FORTIFY is not defined, it
|
||||
will compile away to nothing. If you do not have stdout available, you may
|
||||
wish to set an alternate output function. See Fortify_SetOutputFunc(),
|
||||
below.
|
||||
You will also need to link in fortify.o
|
||||
|
||||
|
||||
|
||||
|
||||
ZFortify INSTALLATION (C++)
|
||||
---------------------------
|
||||
The minimum you need to do for ZFortify is to define the symbol
|
||||
ZFORTIFY, and link zfortify.o. Each source file should also include
|
||||
"zfortify.hpp", but this isn't strictly necessary. If a file doesn't
|
||||
#include "Fortify.hpp", then it's allocations will still be fortified,
|
||||
however you will not have any source-code details in any of the output
|
||||
messages (this will be the case for all libraries, etc, unless you have the
|
||||
source for the library and can recompile it with Fortify).
|
||||
If you do not have stdout available, you may wish to set an alternate
|
||||
output function, or turn on the AUTOMATIC_LOGFILE. See
|
||||
ZFortify_SetOutputFunc() and AUTOMATIC_LOGFILE, below.
|
||||
|
||||
|
||||
|
||||
|
||||
COMPILE TIME CUSTOMIZATIONS
|
||||
---------------------------
|
||||
The files "ufortify.h" and "ufortify.hpp" contain a number of #defines
|
||||
that you can use to customize Fortify's behavior.
|
||||
|
||||
|
||||
#define ZFORTIFY_PROVIDE_ARRAY_NEW
|
||||
|
||||
Some C++ compilers have a separate operator for newing arrays. If your
|
||||
compiler does, you will need to define this symbol. If you are unsure,
|
||||
dont worry about it too much, your program won't compile or link without
|
||||
the correct setting. GCC 2.6.3 and Borland C++ 4.5 both need this symbol.
|
||||
Microsoft C++ 1.5 and SAS 6.5 C++ both dont.
|
||||
|
||||
|
||||
#define FORTIFY_STORAGE
|
||||
|
||||
#define ZFORTIFY_STORAGE
|
||||
|
||||
You can use this to apply a storage type to all of Fortify's exportable
|
||||
functions. If you are putting Fortify in an export library for example,
|
||||
you may need to put __export here, or some such rubbish.
|
||||
|
||||
|
||||
#define FORTIFY_BEFORE_SIZE 32
|
||||
#define FORTIFY_BEFORE_VALUE 0xA3
|
||||
|
||||
#define FORTIFY_AFTER_SIZE 32
|
||||
#define FORTIFY_AFTER_VALUE 0xA5
|
||||
|
||||
#define ZFORTIFY_BEFORE_SIZE 32
|
||||
#define ZFORTIFY_BEFORE_VALUE 0xA3
|
||||
|
||||
#define ZFORTIFY_AFTER_SIZE 32
|
||||
#define ZFORTIFY_AFTER_VALUE 0xA5
|
||||
|
||||
These values define how much "fortification" is placed around each
|
||||
memory block you allocate. Fortify will place _BEFORE_SIZE bytes worth of
|
||||
memory right before your allocation block, and _AFTER_SIZE bytes worth
|
||||
after your allocation block, and these will be initialized to _BEFORE_VALUE
|
||||
and _AFTER_VALUE respectively. If your program then accidentally writes
|
||||
too far beyond the end of the block, for example, Fortify will be able to
|
||||
detect this (so long as you didn't happen to write in _AFTER_VALUE!).
|
||||
|
||||
If you don't want these fortifications to be allocated, specify a
|
||||
_SIZE of 0. Note that the _VALUE parameters are 8 bits.
|
||||
|
||||
|
||||
|
||||
#define FILL_ON_MALLOC
|
||||
#define FILL_ON_MALLOC_VALUE 0xA7
|
||||
|
||||
#define FILL_ON_NEW
|
||||
#define FILL_ON_NEW_VALUE 0xA7
|
||||
|
||||
Programs often rely on uninitialized memory being certain values
|
||||
(usually 0). If you define FILL_ON_NEW, all memory that you new will be
|
||||
initialized to FILL_ON_NEW_VALUE, which you should define to be some horrid
|
||||
value (definately NOT 0). This will encourage all code that relies on
|
||||
uninitialized memory to behave rather differently when Fortify is running.
|
||||
|
||||
|
||||
|
||||
#define FILL_ON_FREE
|
||||
#define FILL_ON_FREE_VALUE 0xA9
|
||||
|
||||
#define FILL_ON_DELETE
|
||||
#define FILL_ON_DELETE_VALUE 0xA9
|
||||
|
||||
Programmers often try to use memory after they've freed it, which can
|
||||
sometimes work (so long as noboby else has modified the memory before you
|
||||
look at it), but is incredibly dangerous and definately bad practice. If
|
||||
FILL_ON_DELETE is defined, all memory you free will be stomped out with
|
||||
FILL_ON_DELETE_VALUE, which ensures that any attempt to read freed memory
|
||||
will give incorrect results.
|
||||
|
||||
|
||||
|
||||
#define CHECK_ALL_MEMORY_ON_MALLOC
|
||||
#define CHECK_ALL_MEMORY_ON_FREE
|
||||
|
||||
#define CHECK_ALL_MEMORY_ON_NEW
|
||||
#define CHECK_ALL_MEMORY_ON_DELETE
|
||||
|
||||
CHECK_ALL_MEMORY_ON... means that for every single memory allocation
|
||||
or deallocation, every single block of memory will be checked. This can
|
||||
considerably slow down programs if you have a large number of blocks
|
||||
allocated. You would normally only need to turn this on if you are trying
|
||||
to pinpoint where a corruption was occurring.
|
||||
A block of memory is always checked when it is freed, so if
|
||||
CHECK_ALL... isn't turned on, corruptions will still be detected
|
||||
eventually.
|
||||
You can also force Fortify to check all memory with a call to
|
||||
Fortify_CheckAllMemory(). If you have a memory corruption you can't find,
|
||||
sprinkling these through the suspect code will help narrow it down.
|
||||
|
||||
|
||||
|
||||
#define PARANOID_FREE
|
||||
|
||||
#define PARANOID_DELETE
|
||||
|
||||
PARANOID_... - This means that zFortify traverses the memory list to
|
||||
ensure the memory you are about to free was really allocated by it. You
|
||||
probably only need this in extreme circumstances. Not having this defined
|
||||
will still trap attempts to free memory that wasn't allocated, unless
|
||||
someone is deliberately trying to fool zFortify.
|
||||
Paranoid mode adds considerable overhead to freeing memory, especially
|
||||
if you are freeing things in the same order you allocated them (Paranoid
|
||||
mode is most efficient if you are freeing things in the reverse order they
|
||||
were allocated).
|
||||
|
||||
|
||||
|
||||
#define WARN_ON_MALLOC_FAIL
|
||||
#define WARN_ON_ZERO_MALLOC
|
||||
#define WARN_ON_FALSE_FAIL
|
||||
#define WARN_ON_UNSIGNED_LONG_OVERFLOW
|
||||
|
||||
#define WARN_ON_NEW_FAIL
|
||||
#define WARN_ON_ZERO_NEW
|
||||
|
||||
These defines enable the output of warning that aren't strictly errors,
|
||||
but can be useful to determine what lead to a program crashing.
|
||||
WARN_ON_NEW_FAIL causes a debug to be issued whenever new fails.
|
||||
WARN_ON_ZERO_NEW causes a debug to be issued whenever a new of a zero
|
||||
byte object is attempted. This is fairly unlikely in C++, and is much more
|
||||
likely when using malloc().
|
||||
WARN_ON_FALSE_FAIL causes a debug to be issued when a new is "false"
|
||||
failed. ZSee Fortify_SetNewFailRate() for more information.
|
||||
WARN_ON_UNSIGNED_LONG_OVERFLOW causes Fortify to check for breaking the
|
||||
32 bit limit. This was more of a problem in 16-bit applications where
|
||||
breaking the 16 bit limit was much more likely. The problem is that
|
||||
Fortify adds a small amount of overhead to a memory block; so in a 16-bit
|
||||
size_t environment, if you tried to allocate 64K, Fortify would make that
|
||||
block bigger than 64K and your allocation would fail due to the presence of
|
||||
Fortify. With size_t being 32 bits for all environments worth programming
|
||||
in, this problem is extremely unlikely (Unless you plan to allocate 4
|
||||
gigabytes).
|
||||
|
||||
|
||||
#define AUTOMATIC_LOG_FILE
|
||||
#define LOG_FILENAME "fortify.log"
|
||||
#define FIRST_ERROR_FUNCTION
|
||||
|
||||
If AUTOMATIC_LOG_FILE is defined (C++ version /ZFortify only), then
|
||||
Fortify will be automatically started for you, Fortify messages sent to the
|
||||
named log file, and a list of unfreed memory dumped on termination (where
|
||||
the log file will be automatically closed for you. If no Fortify was
|
||||
output, the log file will not be altered. There are timestamps in the log
|
||||
file to ensure you're reading the correct messages.
|
||||
FIRST_ERROR_FUNCTION will be called upon generation of the first
|
||||
Fortify message, so that the user can tell a Fortify report has been
|
||||
generated. Otherwise, Fortify would quietly write all this useful stuff
|
||||
out to the log file, and no-one would know to look there!
|
||||
|
||||
|
||||
|
||||
#define FORTIFY_LOCK()
|
||||
#define FORTIFY_UNLOCK()
|
||||
|
||||
#define ZFORTIFY_LOCK()
|
||||
#define ZFORTIFY_UNLOCK()
|
||||
|
||||
In a multi-threaded environment, we need to arbitrate access to the
|
||||
foritfy memory list. This is what ZFORTIFY_LOCK() and ZFORTIFY_UNLOCK()
|
||||
are used for. The calls to ZFORTIFY_LOCK() and ZFORTIFY_UNLOCK() must
|
||||
nest. If no two threads/tasks/processes will be using the same Fortify at
|
||||
the same time, then ZFORTIFY_LOCK() and ZFORTIFY_UNLOCK() can safely be
|
||||
#defined away to nothing.
|
||||
|
||||
|
||||
|
||||
|
||||
RUN TIME CONTROL
|
||||
----------------
|
||||
Fortify can also be controlled at run time with a few special
|
||||
functions, which compile away to nothing if FORTIFY isn't defined, and do
|
||||
nothing if Fortify has been disabled with Fortify_Disable(). These
|
||||
functions all apply to ZFortify as well (The ZFortify versions have a
|
||||
ZFortify_ prefix, of course).
|
||||
|
||||
Fortify_Disable() - This function provides a mechanism to disable
|
||||
Fortify without recompiling all the sourcecode. It can only be called,
|
||||
though, when there is no memory on the Fortify list. (Ideally, at the
|
||||
start of the program before any memory has been allocated). If you call
|
||||
this function when there IS memory on the Fortify list, it will issue an
|
||||
error, and Fortify will not be disabled.
|
||||
|
||||
Fortify_SetOutputFunc(Fortify_OutputFuncPtr Output) - Sets the function
|
||||
used to output all error and diagnostic messages by Fortify. The output
|
||||
function takes a single (const char *) argument, and must be able to handle
|
||||
newlines. The function returns the old pointer.
|
||||
The default output func is a printf() to stdout. Unless you are using
|
||||
AUTOMATIC_LOG_FILE, where the default is to output to the log file.
|
||||
|
||||
Fortify_SetNewFailRate(int Percent) - Fortify will make a new attempt
|
||||
"fail" this "Percent" of the time, even if the memory IS available. Useful
|
||||
to "stress-test" an application. Returns the old value. The fail rate
|
||||
defaults to 0.
|
||||
|
||||
|
||||
|
||||
DIAGNOSTIC FUNCTIONS
|
||||
--------------------
|
||||
Fortify also provides some additional diagnostic functions which can be
|
||||
used to track down memory corruption and memory leaks. If Fortify is
|
||||
disabled, these functions do nothing. If calling these functions directly
|
||||
from a debugger, remember to add the "char *file" and "unsigned long line"
|
||||
paramters to each of the calls. (The ZFortify versions have a
|
||||
ZFortify_ prefix, of course).
|
||||
|
||||
Fortify_CheckPointer(void *uptr) - Returns true if the uptr points to a
|
||||
valid piece of Fortify'd memory. The memory must be on Fortify's list, and
|
||||
it's sentinals must be in tact. If anything is wrong, an error message is
|
||||
issued (Note - if Fortify is disabled, this function always returns true).
|
||||
|
||||
Fortify_CheckAllMemory() - Checks the sentinals of all malloc'd memory.
|
||||
Returns the number of blocks that failed. (If Fortify is disabled, this
|
||||
function always returns 0).
|
||||
|
||||
Fortify_OutputAllMemory() - Outputs the entire list of currently
|
||||
allocated memory. For each block is output it's Address, Size, the
|
||||
SourceFile and Line that allocated it, and the fortify scope from within it
|
||||
was allocated. If there is no memory on the list, this function outputs
|
||||
nothing. It returns the number of blocks on the list, unless Fortify has
|
||||
been disabled, in which case it always returns 0.
|
||||
|
||||
Fortify_DumpAllMemory(scope) - Just like Fortify_OutputAllMemory,
|
||||
except all memory inside the given scope is output, and a hex dump of each
|
||||
block is included in the output.
|
||||
|
||||
Fortify_EnterScope() - enters a level of fortify scope. Returns the
|
||||
new scope level.
|
||||
|
||||
Fortify_LeaveScope() - leaves a level of fortify scope, it also prints
|
||||
a dump of all memory allocated within the scope being left. This can be
|
||||
very useful in tracking down memory leaks in a part of a program. If you
|
||||
place a EnterScope/LeaveScope pair around a set of functions that should
|
||||
have no memory allocated when it's done, Fortify will let you know if this
|
||||
isn't the case.
|
||||
|
||||
|
||||
PROBLEMS WITH THE new AND delete MACROS
|
||||
---------------------------------------
|
||||
Due to limitations of the preprocessor, getting caller sourcecode
|
||||
information isn't as easy as it is for malloc() and free(). The macro for
|
||||
"new" which adds this information onto the new call causes syntax errors if
|
||||
you try to declare a custom new operator. The actual Fortifying works
|
||||
fine, it's just the macro expansion which causes problems.
|
||||
If this happens, you will need to place #undef's and #define's around
|
||||
the offending code (sorry). Alternatively, you can not #include
|
||||
"zfortify.hpp" for the offending file. But remember that none of the
|
||||
allocation done in that file will have sourcecode information.
|
||||
|
||||
eg.
|
||||
#undef new
|
||||
void *X::operator new(size_t) { return malloc(size_t); }
|
||||
#define new Fortify_New
|
||||
|
||||
|
||||
Due to a limitation with delete, Fortify has limited information about
|
||||
where delete is being called called from, and so the the line and source
|
||||
information will often say "delete.0". If a delete is occuring from within
|
||||
another delete, Fortify will always endeavour to report the highest level
|
||||
delete as the caller.
|
||||
|
||||
It should be possible to replace the "new.0" and "delete.0" with the
|
||||
return address of the function, which would be useful when in a debugger,
|
||||
but this would be highly architecture dependant, so I leave that as an
|
||||
exercise for the students :-).
|
||||
|
||||
|
||||
|
||||
WHEN TO USE FORTIFY
|
||||
-------------------
|
||||
The simple answer to this is "All The Time". You should never be
|
||||
without Fortify when you're actually developing software. It will detect
|
||||
your bugs _as_you_write_them_, which makes them a lot easier to find. One
|
||||
programmer who recently started using Fortify when he had a very strange
|
||||
memory problem, spent at least 3 or 4 days tracking down _other_ memory
|
||||
corruption bugs that he wasn't even aware of before the program would stay
|
||||
up long enough to get to his original problem. If he'd been using Fortify
|
||||
from the beginning, this wouldn't have been a problem.
|
||||
Leave fortify enabled until the final test and release of your
|
||||
software. You probably won't want some of the slower options, such as
|
||||
CHECK_ALL_MEMORY_ON_FREE, and PARANOID_FREE. With the exception of those
|
||||
options, Fortify doesn't have a great deal of overhead. If posing a great
|
||||
problem, this overhead can be greatly reduced by cutting down on the size
|
||||
of the fortifications, and turning off the pre/post fills, but each thing
|
||||
you turn off gives fortify less information to work with in tracking your
|
||||
bugs.
|
||||
|
||||
|
28
fourmess.c
28
fourmess.c
@ -393,7 +393,7 @@ static int FourMessStoreIntern(pSICSOBJ self, SConnection * pCon,
|
||||
double fHkl[3], double fPosition[4], char *extra)
|
||||
{
|
||||
pFourMess priv = self->pPrivate;
|
||||
float fSum, fSigma, fTemp, fStep = .0, fPreset =.0;
|
||||
float fSum, fSigma, fTemp, fMF, fStep = .0, fPreset =.0;
|
||||
int i, iLF, iRet, iNP, ii;
|
||||
long *lCounts = NULL;
|
||||
pEVControl pEva = NULL;
|
||||
@ -411,6 +411,7 @@ static int FourMessStoreIntern(pSICSOBJ self, SConnection * pCon,
|
||||
SCWrite(pCon, "ERROR: store: no files open", eLogError);
|
||||
return 0;
|
||||
}
|
||||
priv->count++;
|
||||
|
||||
/* get necessary data */
|
||||
fSum = 0.;
|
||||
@ -485,6 +486,23 @@ static int FourMessStoreIntern(pSICSOBJ self, SConnection * pCon,
|
||||
iRet = EVCGetPos(pEva, pCon, &fTemp);
|
||||
}
|
||||
|
||||
/* get mf */
|
||||
fMF = -777.77;
|
||||
pEva = (pEVControl) FindCommandData(pServ->pSics, "mf",
|
||||
"Environment Controller");
|
||||
if (pEva == NULL) {
|
||||
pPtr = (pDummy) FindCommandData(pServ->pSics, "mf",
|
||||
"RemObject");
|
||||
if (pPtr != NULL) {
|
||||
pDriv = pPtr->pDescriptor->GetInterface(pPtr, DRIVEID);
|
||||
if (pDriv != NULL) {
|
||||
fMF = pDriv->GetValue(pPtr, pCon);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
iRet = EVCGetPos(pEva, pCon, &fMF);
|
||||
}
|
||||
|
||||
/* write profile */
|
||||
if (priv->profFile) {
|
||||
/* collect data */
|
||||
@ -492,12 +510,16 @@ static int FourMessStoreIntern(pSICSOBJ self, SConnection * pCon,
|
||||
GetScanVarStep(priv->pScanner, 0, &fStep);
|
||||
fPreset = GetScanPreset(priv->pScanner);
|
||||
prot = getProtonAverage(priv);
|
||||
/*
|
||||
They rather wanted fMF in place of the proton average which fell victim to the
|
||||
monitor assignement chaos anyway.
|
||||
*/
|
||||
if(extra == NULL){
|
||||
fprintf(priv->profFile, "%3d %7.4f %9.0f %7.3f %12f %s\n", iNP, fStep,
|
||||
fPreset, fTemp, prot, pBueffel);
|
||||
fPreset, fTemp, fMF, pBueffel);
|
||||
} else {
|
||||
fprintf(priv->profFile, "%3d %7.4f %9.0f %7.3f %12f %s %s\n", iNP, fStep,
|
||||
fPreset, fTemp, prot, extra, pBueffel);
|
||||
fPreset, fTemp, fMF, pBueffel,extra);
|
||||
}
|
||||
for (i = 0; i < iNP; i++) {
|
||||
for (ii = 0; ii < 10 && i < iNP; ii++) {
|
||||
|
18
hipadaba.c
18
hipadaba.c
@ -138,6 +138,9 @@ void DeleteNodeData(pHdb node)
|
||||
if (node->name != NULL) {
|
||||
free(node->name);
|
||||
}
|
||||
if (node->path != NULL) {
|
||||
free(node->path);
|
||||
}
|
||||
ReleaseHdbValue(&node->value);
|
||||
node->magic = 000000;
|
||||
|
||||
@ -601,7 +604,7 @@ int compareHdbValue(hdbValue v1, hdbValue v2)
|
||||
}
|
||||
break;
|
||||
case HIPFLOAT:
|
||||
if (ABS(v1.v.doubleValue - v2.v.doubleValue) < .01) {
|
||||
if (ABS(v1.v.doubleValue - v2.v.doubleValue) < .0001) { /* DFC */
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
@ -895,6 +898,7 @@ char *GetHipadabaPath(pHdb node)
|
||||
strcat(pPtr, "/");
|
||||
strcat(pPtr, nodeStack[i]->name);
|
||||
}
|
||||
node->path = pPtr;
|
||||
return pPtr;
|
||||
}
|
||||
|
||||
@ -1167,6 +1171,16 @@ void SetHdbProperty(pHdb node, char *key, char *value)
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int HasHdbProperty(pHdb node, char *key)
|
||||
{
|
||||
if (node != NULL && node->properties != NULL) {
|
||||
return StringDictExists(node->properties, key);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int GetHdbProperty(pHdb node, char *key, char *value, int len)
|
||||
{
|
||||
@ -1180,7 +1194,7 @@ int GetHdbProperty(pHdb node, char *key, char *value, int len)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
char *GetHdbProp(pHdb node, char *key)
|
||||
{
|
||||
if (node != NULL && node->properties != NULL) {
|
||||
if (node != NULL && isHdbNodeValid(node) && node->properties != NULL) {
|
||||
return StringDictGetShort(node->properties, key);
|
||||
} else {
|
||||
return NULL;
|
||||
|
@ -72,6 +72,7 @@ typedef struct __hipadaba {
|
||||
struct __hipadaba *next;
|
||||
struct __hdbcallback *callBackChain;
|
||||
char *name;
|
||||
char *path;
|
||||
hdbValue value;
|
||||
int iprotected;
|
||||
pStringDict properties;
|
||||
@ -446,6 +447,13 @@ void SetHdbProperty(pHdb node, char *key, char *value);
|
||||
* @param len The length of value
|
||||
* @return 0 on failure, 1 on success
|
||||
*/
|
||||
/**
|
||||
* Check if a property exists
|
||||
* @param node The node to get the property from
|
||||
* @param key The properties key
|
||||
* @return 1 or 0 for true or false
|
||||
*/
|
||||
int HasHdbProperty(pHdb node, char *key);
|
||||
int GetHdbProperty(pHdb node, char *key, char *value, int len);
|
||||
/**
|
||||
* get the value of a property
|
||||
|
1
ifile.c
1
ifile.c
@ -47,6 +47,7 @@
|
||||
#include "ifile.h"
|
||||
|
||||
/*====================== Locals ============================================*/
|
||||
IPair *pSICSOptions = NULL;
|
||||
|
||||
static IPair *CreateNewEntry(char *name, char *val, IPair * pN)
|
||||
{
|
||||
|
12
interface.c
12
interface.c
@ -242,6 +242,9 @@ static int DriveTaskFunc(void *data)
|
||||
ExeInterest(pServ->pExecutor,taskData->name, "finished with problem");
|
||||
}
|
||||
traceSys("drive","DriveTask %s finished with state %d", taskData->name,status);
|
||||
if(taskData->pCon->transID > 100000) {
|
||||
SCPrintf(taskData->pCon,eLog,"TASKEND %d", taskData->pCon->transID);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@ -272,6 +275,9 @@ long StartDriveTask(void *obj, SConnection *pCon, char *name, float fTarget)
|
||||
ExeInterest(pServ->pExecutor,name,"started");
|
||||
DevexecLog("START",name);
|
||||
InvokeNewTarget(pServ->pExecutor,name,fTarget);
|
||||
if(pCon->transID > 100000) {
|
||||
SCPrintf(pCon,eLog,"TASKSTART %d", pCon->transID);
|
||||
}
|
||||
|
||||
taskData->id = DRIVEID;
|
||||
taskData->obj = obj;
|
||||
@ -393,6 +399,9 @@ static int CountTaskFunc(void *data)
|
||||
ExeInterest(pServ->pExecutor,taskData->name, "finished with problem");
|
||||
}
|
||||
traceSys("count","CountTask %s finished with state %d", taskData->name,status);
|
||||
if(taskData->pCon->transID > 100000) {
|
||||
SCPrintf(taskData->pCon,eLog,"TASKEND %d", taskData->pCon->transID);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@ -418,6 +427,9 @@ long StartCountTask(void *obj, SConnection *pCon, char *name)
|
||||
}
|
||||
ExeInterest(pServ->pExecutor,name,"started");
|
||||
DevexecLog("START",name);
|
||||
if(pCon->transID > 100000) {
|
||||
SCPrintf(pCon,eLog,"TASKSTART %d", pCon->transID);
|
||||
}
|
||||
|
||||
taskData->id = COUNTID;
|
||||
taskData->obj = obj;
|
||||
|
@ -109,6 +109,8 @@
|
||||
void *pUserData, KillFuncIT pKill);
|
||||
int RemoveCallback(pICallBack pInterface, long iID);
|
||||
int RemoveCallback2(pICallBack pInterface, void *pUserData);
|
||||
int RemoveCallbackUsr(pICallBack self, SICSCallBack pFunc,
|
||||
int (*userfunc)(const void* pContext, const void* pUserData), void *pCtx);
|
||||
int RemoveCallbackCon(pICallBack pInterface, SConnection *pCon);
|
||||
|
||||
int CallbackScript(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
|
1
lld.c
1
lld.c
@ -89,6 +89,7 @@ static int ListInit(int List, int ItemSize)
|
||||
*/
|
||||
Tmp = NODE_MALLOC(List);
|
||||
if (NULL == Tmp) {
|
||||
Tmp = ListControl[List].first;
|
||||
NODE_FREE(Tmp); /* no need to cause memory leaks */
|
||||
ListControl[List].first = NULL; /* or other errors */
|
||||
return ERR_MEMORY; /* even if we're in trouble ... */
|
||||
|
3
logger.c
3
logger.c
@ -397,6 +397,9 @@ static int LoggerMakeDir(char *path)
|
||||
return 0; /* mkdir failed */
|
||||
snprintf(buffer, sizeof buffer, "%s", path);
|
||||
lpath = strlen(buffer);
|
||||
/* Discard any trailing slash characters */
|
||||
while (lpath > 0 && buffer[lpath - 1] == '/')
|
||||
buffer[--lpath] = '\0';
|
||||
do {
|
||||
slash = strrchr(buffer, '/');
|
||||
if (!slash)
|
||||
|
29
logreader.c
29
logreader.c
@ -218,9 +218,7 @@ static int LogReader(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
/* Usage:
|
||||
graph <start time> <end time> [ none <none value> ] np <number of points> <variable> [<variable> ...]
|
||||
graph <start time> <end time> text <variable>
|
||||
graph <start time> <end time> <step> <variable> [<variable> ...]
|
||||
graph <start time> <end time> [ none <none value> | text | np <number of points> ] <variable> [<variable> ...]
|
||||
|
||||
<start time> and <end time> are seconds since epoch (unix time) or, if the value
|
||||
is below one day, a time relative to the actual time
|
||||
@ -230,15 +228,13 @@ static int LogReader(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
<number of points> is the maximal number of points to be returned. If more values
|
||||
are present and the values are numeric, the data is reduced. If the data is not
|
||||
numeric, the last values may be skipped in order to avoid overflow.
|
||||
If np is not given, it is assumed to be very high.
|
||||
|
||||
<variable> is the name of a variable (several vaiables may be given).
|
||||
Note that slashes are converted to dots, and that the first slash is ignored.
|
||||
|
||||
The seconds variant is for text values, which can not be reduced. In any case, all values
|
||||
are returned.
|
||||
|
||||
The third variant is old style and can be replaced by the first variant, where
|
||||
<number of points> = (<start time> - <end time>) / <step> + 2
|
||||
"text" means that the values are not numeric, in this case np is not needed
|
||||
and by default infinitely high
|
||||
|
||||
|
||||
Output format:
|
||||
@ -308,15 +304,16 @@ Statistics *old;
|
||||
to += now;
|
||||
}
|
||||
iarg = 3;
|
||||
type0 = NUMERIC;
|
||||
while (1) {
|
||||
if (iarg >= argc)
|
||||
goto illarg;
|
||||
if (strcasecmp(argv[iarg], "text") == 0) { /* non-numeric values */
|
||||
iarg++;
|
||||
step = 1;
|
||||
type0 = TEXT;
|
||||
np = to - from + 2;
|
||||
break;
|
||||
type0 = TEXT;
|
||||
/* break; */
|
||||
} else if (strcasecmp(argv[iarg], "none") == 0) { /* none */
|
||||
iarg++;
|
||||
if (iarg >= argc)
|
||||
@ -327,7 +324,6 @@ Statistics *old;
|
||||
iarg++;
|
||||
if (iarg >= argc)
|
||||
goto illarg;
|
||||
type0 = NUMERIC;
|
||||
np = strtol(argv[iarg], &p, 0);
|
||||
if (p == argv[iarg])
|
||||
goto illarg;
|
||||
@ -341,14 +337,9 @@ Statistics *old;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
step = strtol(argv[iarg], &p, 0);
|
||||
if (p == argv[iarg])
|
||||
goto illarg;
|
||||
iarg++;
|
||||
if (step <= 0)
|
||||
step = 1;
|
||||
type0 = NUMERIC;
|
||||
np = (from - to) / step + 2;
|
||||
np = to - from + 2;
|
||||
step = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (step <= 0)
|
||||
|
@ -118,6 +118,11 @@ static int LogSetup(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
LoggerChange(logger, period, name);
|
||||
} else {
|
||||
logger = LoggerMake(name, period, !numeric);
|
||||
/* If that failed, we cannot continue - it crashes in the callback */
|
||||
if (logger == NULL) {
|
||||
SCPrintf(pCon, eError, "ERROR: logger %s not created", argv[1]);
|
||||
return 0;
|
||||
}
|
||||
LoggerSetNumeric(logger, numeric);
|
||||
SetHdbProperty(node, "logger_name", name);
|
||||
cb = MakeHipadabaCallback(LoggerUpdateCallback, logger,
|
||||
|
5
macro.c
5
macro.c
@ -68,6 +68,7 @@
|
||||
#include "ifile.h"
|
||||
#include "Dbg.h"
|
||||
#include "servlog.h"
|
||||
#include "sicsglobal.h"
|
||||
#include "stringdict.h"
|
||||
#include "exeman.h"
|
||||
#include "nxcopy.h"
|
||||
@ -493,6 +494,7 @@ int MacroFileEval(SConnection * pCon, SicsInterp * pInter, void *pData,
|
||||
iRun = 0;
|
||||
}
|
||||
if (iChar == (int) '\n') {
|
||||
iLine++;
|
||||
pBueffel[i] = (char) iChar;
|
||||
pBueffel[i + 1] = '\0';
|
||||
Tcl_DStringAppend(&command, pBueffel, -1);
|
||||
@ -500,13 +502,12 @@ int MacroFileEval(SConnection * pCon, SicsInterp * pInter, void *pData,
|
||||
if (Tcl_CommandComplete(pCom)) {
|
||||
FirstWord(pCom, pBueffel);
|
||||
if (FindCommand(pInter, pBueffel) != NULL) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "%s:%d>> %s", pFile, iLine, pCom);
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "%s:%d>> %s", argv[1], iLine, pCom);
|
||||
SCWrite(pCon, pBueffel, eLog);
|
||||
if (pWhere != NULL) {
|
||||
free(pWhere);
|
||||
}
|
||||
pWhere = strdup(pBueffel);
|
||||
iLine++;
|
||||
}
|
||||
iRet = Tcl_Eval(pTcl, pCom);
|
||||
if (iRet != TCL_OK) {
|
||||
|
2
make_gen
2
make_gen
@ -47,7 +47,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
|
||||
histmemsec.o sansbc.o sicsutil.o strlutil.o genbinprot.o trace.o\
|
||||
singlebinb.o taskobj.o sctcomtask.o tasmono.o multicountersec.o \
|
||||
messagepipe.o sicsget.o remoteobject.o pmacprot.o charbychar.o binprot.o \
|
||||
cnvrt.o
|
||||
cnvrt.o tclClock.o tclDate.o tclUnixTime.o
|
||||
|
||||
MOTOROBJ = motor.o simdriv.o
|
||||
COUNTEROBJ = countdriv.o simcter.o counter.o
|
||||
|
@ -1,20 +1,20 @@
|
||||
1.1 2 3 4 5 6 7 8 9 9
|
||||
2 3.1 4 5 6 7 8 9 9 8
|
||||
3 4 5.1 6 7 8 9 9 8 7
|
||||
3 4 5 6.1 7 8 9 9 8 7
|
||||
1 2 3 4 5 7.2 7 8 9 9
|
||||
1 2 3 4 1 6 7 8.3 9 9
|
||||
6 2 3 4 5 6 7 8 9.8 9
|
||||
1 2 3 3 5 6 7 8 9 9.8
|
||||
1 2 3 4 6 6 7 8 9 9
|
||||
6 2 3 4 5 4 7 8 9 9
|
||||
3
|
||||
1
|
||||
4
|
||||
1
|
||||
2
|
||||
3
|
||||
1
|
||||
1
|
||||
2
|
||||
6
|
||||
1.1 2 3 4 5 6 7 8 9 9
|
||||
2 3.1 4 5 6 7 8 9 9 8
|
||||
3 4 5.1 6 7 8 9 9 8 7
|
||||
3 4 5 6.1 7 8 9 9 8 7
|
||||
1 2 3 4 5 7.2 7 8 9 9
|
||||
1 2 3 4 1 6 7 8.3 9 9
|
||||
6 2 3 4 5 6 7 8 9.8 9
|
||||
1 2 3 3 5 6 7 8 9 9.8
|
||||
1 2 3 4 6 6 7 8 9 9
|
||||
6 2 3 4 5 4 7 8 9 9
|
||||
3
|
||||
1
|
||||
4
|
||||
1
|
||||
2
|
||||
3
|
||||
1
|
||||
1
|
||||
2
|
||||
6
|
||||
|
@ -1,62 +1,62 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# file: makefile.msc
|
||||
# desc: makefile for matrix library package under Microsoft C/C++ v7.0
|
||||
# by: patrick ko
|
||||
# date: 16 Apr 94
|
||||
#
|
||||
# note: a slim matrix library matrix.lib will be generated
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
OBJS = matcreat.obj matdump.obj materr.obj matadd.obj matsub.obj \
|
||||
matmul.obj matinv.obj matsolve.obj matdet.obj mattran.obj matdurbn.obj \
|
||||
mattoepz.obj matsubx.obj
|
||||
|
||||
CC = cl -c
|
||||
C = cl
|
||||
|
||||
demo.exe: demo.c matrix.lib
|
||||
$(C) demo.c matrix.lib
|
||||
|
||||
matrix.lib: $(OBJS)
|
||||
lib matrix +matcreat +matdump +materr +matadd.obj ,,
|
||||
lib matrix +matsub +matmul +matinv +matsolve +matdet.obj ,,
|
||||
lib matrix +mattran +matdurbn +mattoepz +matsubx ,,
|
||||
|
||||
matcreat.obj: matcreat.c matrix.h
|
||||
$(CC) matcreat.c
|
||||
|
||||
matdump.obj: matdump.c matrix.h
|
||||
$(CC) matdump.c
|
||||
|
||||
materr.obj: materr.c matrix.h
|
||||
$(CC) materr.c
|
||||
|
||||
matadd.obj: matadd.c matrix.h
|
||||
$(CC) matadd.c
|
||||
|
||||
matsub.obj: matsub.c matrix.h
|
||||
$(CC) matsub.c
|
||||
|
||||
matmul.obj: matmul.c matrix.h
|
||||
$(CC) matmul.c
|
||||
|
||||
matinv.obj: matinv.c matrix.h
|
||||
$(CC) matinv.c
|
||||
|
||||
matsolve.obj: matsolve.c matrix.h
|
||||
$(CC) matsolve.c
|
||||
|
||||
mattran.obj: mattran.c matrix.h
|
||||
$(CC) mattran.c
|
||||
|
||||
matdet.obj: matdet.c matrix.h
|
||||
$(CC) matdet.c
|
||||
|
||||
matdurbn.obj: matdurbn.c matrix.h
|
||||
$(CC) matdurbn.c
|
||||
|
||||
mattoepz.obj: mattoepz.c matrix.h
|
||||
$(CC) mattoepz.c
|
||||
|
||||
matsubx.obj: matsubx.c matrix.h
|
||||
$(CC) matsubx.c
|
||||
#------------------------------------------------------------------------------
|
||||
# file: makefile.msc
|
||||
# desc: makefile for matrix library package under Microsoft C/C++ v7.0
|
||||
# by: patrick ko
|
||||
# date: 16 Apr 94
|
||||
#
|
||||
# note: a slim matrix library matrix.lib will be generated
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
OBJS = matcreat.obj matdump.obj materr.obj matadd.obj matsub.obj \
|
||||
matmul.obj matinv.obj matsolve.obj matdet.obj mattran.obj matdurbn.obj \
|
||||
mattoepz.obj matsubx.obj
|
||||
|
||||
CC = cl -c
|
||||
C = cl
|
||||
|
||||
demo.exe: demo.c matrix.lib
|
||||
$(C) demo.c matrix.lib
|
||||
|
||||
matrix.lib: $(OBJS)
|
||||
lib matrix +matcreat +matdump +materr +matadd.obj ,,
|
||||
lib matrix +matsub +matmul +matinv +matsolve +matdet.obj ,,
|
||||
lib matrix +mattran +matdurbn +mattoepz +matsubx ,,
|
||||
|
||||
matcreat.obj: matcreat.c matrix.h
|
||||
$(CC) matcreat.c
|
||||
|
||||
matdump.obj: matdump.c matrix.h
|
||||
$(CC) matdump.c
|
||||
|
||||
materr.obj: materr.c matrix.h
|
||||
$(CC) materr.c
|
||||
|
||||
matadd.obj: matadd.c matrix.h
|
||||
$(CC) matadd.c
|
||||
|
||||
matsub.obj: matsub.c matrix.h
|
||||
$(CC) matsub.c
|
||||
|
||||
matmul.obj: matmul.c matrix.h
|
||||
$(CC) matmul.c
|
||||
|
||||
matinv.obj: matinv.c matrix.h
|
||||
$(CC) matinv.c
|
||||
|
||||
matsolve.obj: matsolve.c matrix.h
|
||||
$(CC) matsolve.c
|
||||
|
||||
mattran.obj: mattran.c matrix.h
|
||||
$(CC) mattran.c
|
||||
|
||||
matdet.obj: matdet.c matrix.h
|
||||
$(CC) matdet.c
|
||||
|
||||
matdurbn.obj: matdurbn.c matrix.h
|
||||
$(CC) matdurbn.c
|
||||
|
||||
mattoepz.obj: mattoepz.c matrix.h
|
||||
$(CC) mattoepz.c
|
||||
|
||||
matsubx.obj: matsubx.c matrix.h
|
||||
$(CC) matsubx.c
|
||||
|
@ -1,74 +1,74 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# file: makefile.tc
|
||||
# desc: makefile for matrix library package under Turbo C v2.0
|
||||
# by: patrick ko
|
||||
# date: 16 Apr 94
|
||||
#
|
||||
# note: a slim matrix library matrix.lib will be generated
|
||||
#------------------------------------------------------------------------------
|
||||
DRIVE = C:
|
||||
|
||||
OBJS = matcreat.obj matdump.obj materr.obj matadd.obj matsub.obj \
|
||||
matmul.obj matinv.obj matsolve.obj matdet.obj mattran.obj matdurbn.obj \
|
||||
mattoepz.obj matsubx.obj
|
||||
|
||||
LIB = -L$(DRIVE)\TC\LIB
|
||||
INC = -I$(DRIVE)\TC\INCLUDE
|
||||
CC = tcc -c -mh $(INC)
|
||||
C = tcc -mh $(LIB) $(INC)
|
||||
LL = tlib matrix.lib
|
||||
|
||||
demo.exe: demo.c $(OBJS)
|
||||
$(C) demo.c matrix.lib
|
||||
|
||||
matcreat.obj: matcreat.c matrix.h
|
||||
$(CC) matcreat.c
|
||||
$(LL) -+matcreat.obj
|
||||
|
||||
matdump.obj: matdump.c matrix.h
|
||||
$(CC) matdump.c
|
||||
$(LL) -+matdump.obj
|
||||
|
||||
materr.obj: materr.c matrix.h
|
||||
$(CC) materr.c
|
||||
$(LL) -+materr.obj
|
||||
|
||||
matadd.obj: matadd.c matrix.h
|
||||
$(CC) matadd.c
|
||||
$(LL) -+matadd.obj
|
||||
|
||||
matsub.obj: matsub.c matrix.h
|
||||
$(CC) matsub.c
|
||||
$(LL) -+matsub.obj
|
||||
|
||||
matmul.obj: matmul.c matrix.h
|
||||
$(CC) matmul.c
|
||||
$(LL) -+matmul.obj
|
||||
|
||||
matinv.obj: matinv.c matrix.h
|
||||
$(CC) matinv.c
|
||||
$(LL) -+matinv.obj
|
||||
|
||||
matsolve.obj: matsolve.c matrix.h
|
||||
$(CC) matsolve.c
|
||||
$(LL) -+matsolve.obj
|
||||
|
||||
mattran.obj: mattran.c matrix.h
|
||||
$(CC) mattran.c
|
||||
$(LL) -+mattran.obj
|
||||
|
||||
matdet.obj: matdet.c matrix.h
|
||||
$(CC) matdet.c
|
||||
$(LL) -+matdet.obj
|
||||
|
||||
matdurbn.obj: matdurbn.c matrix.h
|
||||
$(CC) matdurbn.c
|
||||
$(LL) -+matdurbn.obj
|
||||
|
||||
mattoepz.obj: mattoepz.c matrix.h
|
||||
$(CC) mattoepz.c
|
||||
$(LL) -+mattoepz.obj
|
||||
|
||||
matsubx.obj: matsubx.c matrix.h
|
||||
$(CC) matsubx.c
|
||||
$(LL) -+matsubx.obj
|
||||
#------------------------------------------------------------------------------
|
||||
# file: makefile.tc
|
||||
# desc: makefile for matrix library package under Turbo C v2.0
|
||||
# by: patrick ko
|
||||
# date: 16 Apr 94
|
||||
#
|
||||
# note: a slim matrix library matrix.lib will be generated
|
||||
#------------------------------------------------------------------------------
|
||||
DRIVE = C:
|
||||
|
||||
OBJS = matcreat.obj matdump.obj materr.obj matadd.obj matsub.obj \
|
||||
matmul.obj matinv.obj matsolve.obj matdet.obj mattran.obj matdurbn.obj \
|
||||
mattoepz.obj matsubx.obj
|
||||
|
||||
LIB = -L$(DRIVE)\TC\LIB
|
||||
INC = -I$(DRIVE)\TC\INCLUDE
|
||||
CC = tcc -c -mh $(INC)
|
||||
C = tcc -mh $(LIB) $(INC)
|
||||
LL = tlib matrix.lib
|
||||
|
||||
demo.exe: demo.c $(OBJS)
|
||||
$(C) demo.c matrix.lib
|
||||
|
||||
matcreat.obj: matcreat.c matrix.h
|
||||
$(CC) matcreat.c
|
||||
$(LL) -+matcreat.obj
|
||||
|
||||
matdump.obj: matdump.c matrix.h
|
||||
$(CC) matdump.c
|
||||
$(LL) -+matdump.obj
|
||||
|
||||
materr.obj: materr.c matrix.h
|
||||
$(CC) materr.c
|
||||
$(LL) -+materr.obj
|
||||
|
||||
matadd.obj: matadd.c matrix.h
|
||||
$(CC) matadd.c
|
||||
$(LL) -+matadd.obj
|
||||
|
||||
matsub.obj: matsub.c matrix.h
|
||||
$(CC) matsub.c
|
||||
$(LL) -+matsub.obj
|
||||
|
||||
matmul.obj: matmul.c matrix.h
|
||||
$(CC) matmul.c
|
||||
$(LL) -+matmul.obj
|
||||
|
||||
matinv.obj: matinv.c matrix.h
|
||||
$(CC) matinv.c
|
||||
$(LL) -+matinv.obj
|
||||
|
||||
matsolve.obj: matsolve.c matrix.h
|
||||
$(CC) matsolve.c
|
||||
$(LL) -+matsolve.obj
|
||||
|
||||
mattran.obj: mattran.c matrix.h
|
||||
$(CC) mattran.c
|
||||
$(LL) -+mattran.obj
|
||||
|
||||
matdet.obj: matdet.c matrix.h
|
||||
$(CC) matdet.c
|
||||
$(LL) -+matdet.obj
|
||||
|
||||
matdurbn.obj: matdurbn.c matrix.h
|
||||
$(CC) matdurbn.c
|
||||
$(LL) -+matdurbn.obj
|
||||
|
||||
mattoepz.obj: mattoepz.c matrix.h
|
||||
$(CC) mattoepz.c
|
||||
$(LL) -+mattoepz.obj
|
||||
|
||||
matsubx.obj: matsubx.c matrix.h
|
||||
$(CC) matsubx.c
|
||||
$(LL) -+matsubx.obj
|
||||
|
@ -1,54 +1,54 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# file: makefile.ux
|
||||
# desc: makefile for matrix library package under Unix
|
||||
# by: patrick ko
|
||||
# date: 16 Apr 94
|
||||
#------------------------------------------------------------------------------
|
||||
OBJS = matcreat.o matdump.o materr.o matadd.o matsub.o \
|
||||
matmul.o matinv.o matsolve.o mattran.o matdet.o mattoepz.o matdurbn.o
|
||||
|
||||
CC = cc -c
|
||||
C = cc
|
||||
CO = -lm -g
|
||||
|
||||
demo: demo.c $(OBJS)
|
||||
$(C) demo.c -o demo $(OBJS) $(CO)
|
||||
|
||||
matcreat.o: matcreat.c matrix.h
|
||||
$(CC) matcreat.c
|
||||
|
||||
matdump.o: matdump.c matrix.h
|
||||
$(CC) matdump.c
|
||||
|
||||
materr.o: materr.c matrix.h
|
||||
$(CC) materr.c
|
||||
|
||||
matadd.o: matadd.c matrix.h
|
||||
$(CC) matadd.c
|
||||
|
||||
matsub.o: matsub.c matrix.h
|
||||
$(CC) matsub.c
|
||||
|
||||
matmul.o: matmul.c matrix.h
|
||||
$(CC) matmul.c
|
||||
|
||||
matinv.o: matinv.c matrix.h
|
||||
$(CC) matinv.c
|
||||
|
||||
matsolve.o: matsolve.c matrix.h
|
||||
$(CC) matsolve.c
|
||||
|
||||
mattran.o: mattran.c matrix.h
|
||||
$(CC) mattran.c
|
||||
|
||||
matdet.o: matdet.c matrix.h
|
||||
$(CC) matdet.c
|
||||
|
||||
mattoepz.o: mattoepz.c matrix.h
|
||||
$(CC) mattoepz.c
|
||||
|
||||
matdurbn.o: matdurbn.c matrix.h
|
||||
$(CC) matdurbn.c
|
||||
|
||||
matsubx.o: matsubx.c matrix.h
|
||||
$(CC) matsubx.c
|
||||
#------------------------------------------------------------------------------
|
||||
# file: makefile.ux
|
||||
# desc: makefile for matrix library package under Unix
|
||||
# by: patrick ko
|
||||
# date: 16 Apr 94
|
||||
#------------------------------------------------------------------------------
|
||||
OBJS = matcreat.o matdump.o materr.o matadd.o matsub.o \
|
||||
matmul.o matinv.o matsolve.o mattran.o matdet.o mattoepz.o matdurbn.o
|
||||
|
||||
CC = cc -c
|
||||
C = cc
|
||||
CO = -lm -g
|
||||
|
||||
demo: demo.c $(OBJS)
|
||||
$(C) demo.c -o demo $(OBJS) $(CO)
|
||||
|
||||
matcreat.o: matcreat.c matrix.h
|
||||
$(CC) matcreat.c
|
||||
|
||||
matdump.o: matdump.c matrix.h
|
||||
$(CC) matdump.c
|
||||
|
||||
materr.o: materr.c matrix.h
|
||||
$(CC) materr.c
|
||||
|
||||
matadd.o: matadd.c matrix.h
|
||||
$(CC) matadd.c
|
||||
|
||||
matsub.o: matsub.c matrix.h
|
||||
$(CC) matsub.c
|
||||
|
||||
matmul.o: matmul.c matrix.h
|
||||
$(CC) matmul.c
|
||||
|
||||
matinv.o: matinv.c matrix.h
|
||||
$(CC) matinv.c
|
||||
|
||||
matsolve.o: matsolve.c matrix.h
|
||||
$(CC) matsolve.c
|
||||
|
||||
mattran.o: mattran.c matrix.h
|
||||
$(CC) mattran.c
|
||||
|
||||
matdet.o: matdet.c matrix.h
|
||||
$(CC) matdet.c
|
||||
|
||||
mattoepz.o: mattoepz.c matrix.h
|
||||
$(CC) mattoepz.c
|
||||
|
||||
matdurbn.o: matdurbn.c matrix.h
|
||||
$(CC) matdurbn.c
|
||||
|
||||
matsubx.o: matsubx.c matrix.h
|
||||
$(CC) matsubx.c
|
||||
|
224
matrix/READ.ME
224
matrix/READ.ME
@ -1,112 +1,112 @@
|
||||
-------------------------------------------------------------------------------
|
||||
Small Matrix Toolbox for C programmers
|
||||
version 0.42
|
||||
(Support Unix and DOS)
|
||||
|
||||
by Patrick KO Shu-pui
|
||||
|
||||
Copyright (c) 1992, 1993, 1994 All Rights Reserved.
|
||||
-------------------------------------------------------------------------------
|
||||
ADDRESS TO CONTACT:
|
||||
|
||||
fidonet: 6:700/132 BiG Programming Club
|
||||
[852] 663-0223 19.2 kbps
|
||||
[852] 663-0236 16.8 kbps
|
||||
|
||||
internet: pko@hk.super.net
|
||||
|
||||
mailing: Patrick Ko
|
||||
G.P.O. Box 7468
|
||||
Hong Kong
|
||||
-------------------------------------------------------------------------------
|
||||
MATRX042.ZIP contains
|
||||
|
||||
READ .ME - this file
|
||||
DEMO .C - demo how to use this package
|
||||
DEMO .DAT - demo data
|
||||
DEMO .EXE - demo executable for DOS
|
||||
MAKEFILE.MSC - makefile for Microsoft C/C++ 7.0 on DOS
|
||||
MAKEFILE.TC - makefile for Turbo C 2.0 on DOS
|
||||
MAKEFILE.UX - makefile for Unix
|
||||
MATRIX .DOC - matrix toolbox interface document
|
||||
MATRIX .H - matrix header file (must include it)
|
||||
MATADD .C - matrix addition
|
||||
MATCREAT.C - matrix creation
|
||||
MATDET .C - find minor, cofactor, determinant
|
||||
MATDUMP .C - matrix dump
|
||||
MATERR .C - matrix error handling routine
|
||||
MATINV .C - matrix inversion
|
||||
MATMUL .C - matrix multiplication
|
||||
MATSOLVE.C - linear equations solver
|
||||
MATSUB .C - matrix substraction
|
||||
MATSUBX .C - submatrix operation
|
||||
MATTOEPZ.C - create symmetric Toeplitz matrix
|
||||
MATDURBN.C - Symmetrix Toeplitz matrix fast solving algorithm
|
||||
MATTRAN .C - matrix transpose
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
WHATS NEW in v0.1:
|
||||
- +, -, *, inverse matrix operations
|
||||
|
||||
WHATS NEW in v0.2:
|
||||
- Linear equation solver
|
||||
- C-programmer-friendly C sources
|
||||
|
||||
WHATS NEW in v0.3:
|
||||
- better data structure (more Object-Oriented)
|
||||
- finding minors, cofactors, determinants
|
||||
- Levinson-Durbin algorithm for symmetric Toeplitz matrix
|
||||
|
||||
WHATS NEW in v0.4:
|
||||
- Revised method for minors, cofactors and determinants
|
||||
whose time complexity is T(n^3) instead of nearly T(n!).
|
||||
This is important when you want to find the determinant
|
||||
of a matrix whose size is over 10 x 10.
|
||||
- submatrix operator
|
||||
- matrix formmated dump function
|
||||
- brief matrix toolbox interface document included
|
||||
|
||||
WHATS NEW in v0.41:
|
||||
- bug fix for unit matrix creation
|
||||
|
||||
WHATS NEW in v0.42:
|
||||
- support Microsoft C/C++ 7.0
|
||||
|
||||
HOW TO COMPILE:
|
||||
|
||||
1. All Unix environment - make -f makefile.ux
|
||||
2. DOS (Turbo C v2.0) - make -fmakefile.tc
|
||||
3. DOS (Microsoft C/C++ v7.0) - nmake -fmakefile.msc
|
||||
|
||||
REFERENCES
|
||||
|
||||
[1] Mary L.Boas, "Mathematical Methods in the Physical Sciene,"
|
||||
John Wiley & Sons, 2nd Ed., 1983. Chap 3.
|
||||
|
||||
[2] Kendall E.Atkinson, "An Introduction to Numberical Analysis,"
|
||||
John Wiley & Sons, 1978.
|
||||
|
||||
[3] Shuzo Saito, Kazuo Nakata, "Fundamentals of Speech Signal
|
||||
Processing," Academic Press, 1985.
|
||||
|
||||
[4] Alfred V.Aho, John E.Hopcroft, Jeffrey D.Ullman, "The Design
|
||||
and Analysis of Computer Algorithms," 1974.
|
||||
|
||||
AUTHOR
|
||||
All the sources are written by Patrick KO Shu Pui
|
||||
BiG Programming Club (6:700/132, fidonet)
|
||||
|
||||
===============================================================================
|
||||
AUTHORIZATION NOTICE
|
||||
|
||||
This C source package MATRX042.ZIP is FREE for ACADEMIC purpose only.
|
||||
|
||||
For COMMERCIAL use, authorization is required from the author.
|
||||
Please send US$25 for registration.
|
||||
===============================================================================
|
||||
DISCLAIMER (I hate this but I have to do that)
|
||||
|
||||
You are on your own risk - the author is not responsible for any lost due
|
||||
to the use of this toolbox.
|
||||
===============================================================================
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Small Matrix Toolbox for C programmers
|
||||
version 0.42
|
||||
(Support Unix and DOS)
|
||||
|
||||
by Patrick KO Shu-pui
|
||||
|
||||
Copyright (c) 1992, 1993, 1994 All Rights Reserved.
|
||||
-------------------------------------------------------------------------------
|
||||
ADDRESS TO CONTACT:
|
||||
|
||||
fidonet: 6:700/132 BiG Programming Club
|
||||
[852] 663-0223 19.2 kbps
|
||||
[852] 663-0236 16.8 kbps
|
||||
|
||||
internet: pko@hk.super.net
|
||||
|
||||
mailing: Patrick Ko
|
||||
G.P.O. Box 7468
|
||||
Hong Kong
|
||||
-------------------------------------------------------------------------------
|
||||
MATRX042.ZIP contains
|
||||
|
||||
READ .ME - this file
|
||||
DEMO .C - demo how to use this package
|
||||
DEMO .DAT - demo data
|
||||
DEMO .EXE - demo executable for DOS
|
||||
MAKEFILE.MSC - makefile for Microsoft C/C++ 7.0 on DOS
|
||||
MAKEFILE.TC - makefile for Turbo C 2.0 on DOS
|
||||
MAKEFILE.UX - makefile for Unix
|
||||
MATRIX .DOC - matrix toolbox interface document
|
||||
MATRIX .H - matrix header file (must include it)
|
||||
MATADD .C - matrix addition
|
||||
MATCREAT.C - matrix creation
|
||||
MATDET .C - find minor, cofactor, determinant
|
||||
MATDUMP .C - matrix dump
|
||||
MATERR .C - matrix error handling routine
|
||||
MATINV .C - matrix inversion
|
||||
MATMUL .C - matrix multiplication
|
||||
MATSOLVE.C - linear equations solver
|
||||
MATSUB .C - matrix substraction
|
||||
MATSUBX .C - submatrix operation
|
||||
MATTOEPZ.C - create symmetric Toeplitz matrix
|
||||
MATDURBN.C - Symmetrix Toeplitz matrix fast solving algorithm
|
||||
MATTRAN .C - matrix transpose
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
WHATS NEW in v0.1:
|
||||
- +, -, *, inverse matrix operations
|
||||
|
||||
WHATS NEW in v0.2:
|
||||
- Linear equation solver
|
||||
- C-programmer-friendly C sources
|
||||
|
||||
WHATS NEW in v0.3:
|
||||
- better data structure (more Object-Oriented)
|
||||
- finding minors, cofactors, determinants
|
||||
- Levinson-Durbin algorithm for symmetric Toeplitz matrix
|
||||
|
||||
WHATS NEW in v0.4:
|
||||
- Revised method for minors, cofactors and determinants
|
||||
whose time complexity is T(n^3) instead of nearly T(n!).
|
||||
This is important when you want to find the determinant
|
||||
of a matrix whose size is over 10 x 10.
|
||||
- submatrix operator
|
||||
- matrix formmated dump function
|
||||
- brief matrix toolbox interface document included
|
||||
|
||||
WHATS NEW in v0.41:
|
||||
- bug fix for unit matrix creation
|
||||
|
||||
WHATS NEW in v0.42:
|
||||
- support Microsoft C/C++ 7.0
|
||||
|
||||
HOW TO COMPILE:
|
||||
|
||||
1. All Unix environment - make -f makefile.ux
|
||||
2. DOS (Turbo C v2.0) - make -fmakefile.tc
|
||||
3. DOS (Microsoft C/C++ v7.0) - nmake -fmakefile.msc
|
||||
|
||||
REFERENCES
|
||||
|
||||
[1] Mary L.Boas, "Mathematical Methods in the Physical Sciene,"
|
||||
John Wiley & Sons, 2nd Ed., 1983. Chap 3.
|
||||
|
||||
[2] Kendall E.Atkinson, "An Introduction to Numberical Analysis,"
|
||||
John Wiley & Sons, 1978.
|
||||
|
||||
[3] Shuzo Saito, Kazuo Nakata, "Fundamentals of Speech Signal
|
||||
Processing," Academic Press, 1985.
|
||||
|
||||
[4] Alfred V.Aho, John E.Hopcroft, Jeffrey D.Ullman, "The Design
|
||||
and Analysis of Computer Algorithms," 1974.
|
||||
|
||||
AUTHOR
|
||||
All the sources are written by Patrick KO Shu Pui
|
||||
BiG Programming Club (6:700/132, fidonet)
|
||||
|
||||
===============================================================================
|
||||
AUTHORIZATION NOTICE
|
||||
|
||||
This C source package MATRX042.ZIP is FREE for ACADEMIC purpose only.
|
||||
|
||||
For COMMERCIAL use, authorization is required from the author.
|
||||
Please send US$25 for registration.
|
||||
===============================================================================
|
||||
DISCLAIMER (I hate this but I have to do that)
|
||||
|
||||
You are on your own risk - the author is not responsible for any lost due
|
||||
to the use of this toolbox.
|
||||
===============================================================================
|
||||
|
||||
|
182
matrix/demo.c
182
matrix/demo.c
@ -1,92 +1,92 @@
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
* file: demo.c
|
||||
* desc: demostrate how to use Patrick's matrix toolbox
|
||||
* by: ko shu pui, patrick
|
||||
* date: 24 nov 91 v0.1
|
||||
* revi: 14 may 92 v0.2
|
||||
* 24 may 92 v0.4
|
||||
* ref:
|
||||
* [1] Mary L.Boas, "Mathematical Methods in the Physical Sciene,"
|
||||
* John Wiley & Sons, 2nd Ed., 1983. Chap 3.
|
||||
*
|
||||
* [2] Kendall E.Atkinson, "An Introduction to Numberical Analysis,"
|
||||
* John Wiley & Sons, 1978.
|
||||
*
|
||||
* [3] Alfred V.Aho, John E.Hopcroft, Jeffrey D.Ullman, "The Design
|
||||
* and Analysis of Computer Algorithms," 1974.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "matrix.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
MATRIX A, B, X, M;
|
||||
FILE *fp;
|
||||
double result;
|
||||
time_t t1, t2;
|
||||
int tinv, tdet, tmul;
|
||||
|
||||
A = mat_creat( 10, 10, UNDEFINED );
|
||||
B = mat_creat( 10, 1, UNDEFINED );
|
||||
|
||||
if ((fp = fopen( "demo.dat", "r" )) == NULL)
|
||||
{
|
||||
fprintf( stderr, "file cannot be opened\n" );
|
||||
exit (0);
|
||||
}
|
||||
|
||||
fgetmat( A, fp );
|
||||
printf( "|- Matrix A -|\n");
|
||||
mat_dumpf( A, "%+06.1f " );
|
||||
|
||||
t1 = time(&t1);
|
||||
result = mat_det(A);
|
||||
t2 = time(&t2);
|
||||
tdet = t2 - t1;
|
||||
printf( "\n\nDet(A) = %f\n", result );
|
||||
|
||||
printf( "|- Inv A -|\n");
|
||||
t1 = time(&t1);
|
||||
X = mat_inv( A );
|
||||
t2 = time(&t2);
|
||||
tinv = t2 - t1;
|
||||
|
||||
if (X == NULL)
|
||||
printf( "A is a singular matrix\n" );
|
||||
else
|
||||
{
|
||||
mat_dumpf(X, "%+06.1f ");
|
||||
|
||||
printf( "|- A x Inv A -|\n");
|
||||
t1 = time(&t1);
|
||||
M = mat_mul( X, A );
|
||||
t2 = time(&t2);
|
||||
tmul = t2 - t1;
|
||||
mat_dumpf( M, "%+06.1f " );
|
||||
|
||||
mat_free(M);
|
||||
mat_free(X);
|
||||
}
|
||||
|
||||
fgetmat( B, fp );
|
||||
printf( "|- Matrix B -|\n");
|
||||
mat_dumpf( B, "%+06.1f " );
|
||||
|
||||
printf( "|- A x B -|\n");
|
||||
mat_free(mat_dumpf(mat_mul(A, B), "%+06.1f "));
|
||||
|
||||
printf( "time for finding 10 x 10 matrix inversion is less than %d secs\n", tinv );
|
||||
printf( "time for finding 10 x 10 matrix determinant is less than %d secs\n", tdet );
|
||||
printf( "time for finding 10 x 10 matrix multiplication is less than %d secs\n", tmul );
|
||||
|
||||
mat_free( A );
|
||||
mat_free( B );
|
||||
|
||||
fclose(fp);
|
||||
|
||||
}
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
* file: demo.c
|
||||
* desc: demostrate how to use Patrick's matrix toolbox
|
||||
* by: ko shu pui, patrick
|
||||
* date: 24 nov 91 v0.1
|
||||
* revi: 14 may 92 v0.2
|
||||
* 24 may 92 v0.4
|
||||
* ref:
|
||||
* [1] Mary L.Boas, "Mathematical Methods in the Physical Sciene,"
|
||||
* John Wiley & Sons, 2nd Ed., 1983. Chap 3.
|
||||
*
|
||||
* [2] Kendall E.Atkinson, "An Introduction to Numberical Analysis,"
|
||||
* John Wiley & Sons, 1978.
|
||||
*
|
||||
* [3] Alfred V.Aho, John E.Hopcroft, Jeffrey D.Ullman, "The Design
|
||||
* and Analysis of Computer Algorithms," 1974.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "matrix.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
MATRIX A, B, X, M;
|
||||
FILE *fp;
|
||||
double result;
|
||||
time_t t1, t2;
|
||||
int tinv, tdet, tmul;
|
||||
|
||||
A = mat_creat( 10, 10, UNDEFINED );
|
||||
B = mat_creat( 10, 1, UNDEFINED );
|
||||
|
||||
if ((fp = fopen( "demo.dat", "r" )) == NULL)
|
||||
{
|
||||
fprintf( stderr, "file cannot be opened\n" );
|
||||
exit (0);
|
||||
}
|
||||
|
||||
fgetmat( A, fp );
|
||||
printf( "|- Matrix A -|\n");
|
||||
mat_dumpf( A, "%+06.1f " );
|
||||
|
||||
t1 = time(&t1);
|
||||
result = mat_det(A);
|
||||
t2 = time(&t2);
|
||||
tdet = t2 - t1;
|
||||
printf( "\n\nDet(A) = %f\n", result );
|
||||
|
||||
printf( "|- Inv A -|\n");
|
||||
t1 = time(&t1);
|
||||
X = mat_inv( A );
|
||||
t2 = time(&t2);
|
||||
tinv = t2 - t1;
|
||||
|
||||
if (X == NULL)
|
||||
printf( "A is a singular matrix\n" );
|
||||
else
|
||||
{
|
||||
mat_dumpf(X, "%+06.1f ");
|
||||
|
||||
printf( "|- A x Inv A -|\n");
|
||||
t1 = time(&t1);
|
||||
M = mat_mul( X, A );
|
||||
t2 = time(&t2);
|
||||
tmul = t2 - t1;
|
||||
mat_dumpf( M, "%+06.1f " );
|
||||
|
||||
mat_free(M);
|
||||
mat_free(X);
|
||||
}
|
||||
|
||||
fgetmat( B, fp );
|
||||
printf( "|- Matrix B -|\n");
|
||||
mat_dumpf( B, "%+06.1f " );
|
||||
|
||||
printf( "|- A x B -|\n");
|
||||
mat_free(mat_dumpf(mat_mul(A, B), "%+06.1f "));
|
||||
|
||||
printf( "time for finding 10 x 10 matrix inversion is less than %d secs\n", tinv );
|
||||
printf( "time for finding 10 x 10 matrix determinant is less than %d secs\n", tdet );
|
||||
printf( "time for finding 10 x 10 matrix multiplication is less than %d secs\n", tmul );
|
||||
|
||||
mat_free( A );
|
||||
mat_free( B );
|
||||
|
||||
fclose(fp);
|
||||
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
* %I
|
||||
* Written by: Kim Lefmann
|
||||
* Date: October 4, 1997
|
||||
* Version: $Revision: 1.19 $
|
||||
* Version: $Revision$
|
||||
* Origin: Risoe
|
||||
* Release: McStas 1.6
|
||||
* Modified to write monitor file for SICS: Mark Koennecke, June 2005
|
||||
|
@ -10,7 +10,7 @@
|
||||
* %I
|
||||
* Written by: Kim Lefmann
|
||||
* Date: Feb 3, 1998
|
||||
* Version: $Revision: 1.2 $
|
||||
* Version: $Revision$
|
||||
* Origin: Risoe
|
||||
* Release: McStas 1.6
|
||||
*
|
||||
|
@ -30,9 +30,9 @@
|
||||
*
|
||||
* Usage: Automatically embbeded in the c code.
|
||||
*
|
||||
* $Id: dmcafter.c,v 1.1 2007/01/30 03:19:43 koennecke Exp $
|
||||
* $Id$
|
||||
*
|
||||
* $Log: dmcafter.c,v $
|
||||
* $Log$
|
||||
* Revision 1.1 2007/01/30 03:19:43 koennecke
|
||||
* - Fixed state monitor eclipse commit problems. Siiiiiiiggggghhhhhh!
|
||||
*
|
||||
@ -87,7 +87,7 @@
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef MCSTAS_R_H
|
||||
#define MCSTAS_R_H "$Revision: 1.1 $"
|
||||
#define MCSTAS_R_H "$Revision$"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
@ -569,9 +569,9 @@ void mcsiminfo_close(void);
|
||||
*
|
||||
* Usage: Automatically embbeded in the c code whenever required.
|
||||
*
|
||||
* $Id: dmcafter.c,v 1.1 2007/01/30 03:19:43 koennecke Exp $
|
||||
* $Id$
|
||||
*
|
||||
* $Log: dmcafter.c,v $
|
||||
* $Log$
|
||||
* Revision 1.1 2007/01/30 03:19:43 koennecke
|
||||
* - Fixed state monitor eclipse commit problems. Siiiiiiiggggghhhhhh!
|
||||
*
|
||||
@ -4356,9 +4356,9 @@ MCNUM mccDet9_zmax;
|
||||
* %include "read_table-lib"
|
||||
*
|
||||
*
|
||||
* $Id: dmcafter.c,v 1.1 2007/01/30 03:19:43 koennecke Exp $
|
||||
* $Id$
|
||||
*
|
||||
* $Log: dmcafter.c,v $
|
||||
* $Log$
|
||||
* Revision 1.1 2007/01/30 03:19:43 koennecke
|
||||
* - Fixed state monitor eclipse commit problems. Siiiiiiiggggghhhhhh!
|
||||
*
|
||||
@ -4433,9 +4433,9 @@ static void Table_Stat(t_Table *mc_rt_Table);
|
||||
* Usage: within SHARE
|
||||
* %include "read_table-lib"
|
||||
*
|
||||
* $Id: dmcafter.c,v 1.1 2007/01/30 03:19:43 koennecke Exp $
|
||||
* $Id$
|
||||
*
|
||||
* $Log: dmcafter.c,v $
|
||||
* $Log$
|
||||
* Revision 1.1 2007/01/30 03:19:43 koennecke
|
||||
* - Fixed state monitor eclipse commit problems. Siiiiiiiggggghhhhhh!
|
||||
*
|
||||
@ -5284,9 +5284,9 @@ long Virtual_input_Read_Input(char *aFile, char *aType, t_Table *aTable, long *a
|
||||
* Usage: within SHARE
|
||||
* %include "monitor_nd-lib"
|
||||
*
|
||||
* $Id: dmcafter.c,v 1.1 2007/01/30 03:19:43 koennecke Exp $
|
||||
* $Id$
|
||||
*
|
||||
* $Log: dmcafter.c,v $
|
||||
* $Log$
|
||||
* Revision 1.1 2007/01/30 03:19:43 koennecke
|
||||
* - Fixed state monitor eclipse commit problems. Siiiiiiiggggghhhhhh!
|
||||
*
|
||||
@ -5460,9 +5460,9 @@ void Monitor_nD_McDisplay(MonitornD_Defines_type *,
|
||||
* Usage: within SHARE
|
||||
* %include "monitor_nd-lib"
|
||||
*
|
||||
* $Id: dmcafter.c,v 1.1 2007/01/30 03:19:43 koennecke Exp $
|
||||
* $Id$
|
||||
*
|
||||
* $Log: dmcafter.c,v $
|
||||
* $Log$
|
||||
* Revision 1.1 2007/01/30 03:19:43 koennecke
|
||||
* - Fixed state monitor eclipse commit problems. Siiiiiiiggggghhhhhh!
|
||||
*
|
||||
|
3
modriv.h
3
modriv.h
@ -14,6 +14,7 @@
|
||||
#define MOTREDO -1
|
||||
#define MOTFAIL 0
|
||||
#define MOTOK 1
|
||||
#define TEXTPARLEN 1024
|
||||
|
||||
typedef struct __AbstractMoDriv {
|
||||
/* general motor driver interface
|
||||
@ -33,6 +34,7 @@ typedef struct __AbstractMoDriv {
|
||||
char *name, float newValue);
|
||||
void (*ListDriverPar) (void *self, char *motorName, SConnection * pCon);
|
||||
void (*KillPrivate) (void *self);
|
||||
int (*GetDriverTextPar) (void *self, char *name, char *textPar);
|
||||
} MotorDriver;
|
||||
|
||||
/* the first fields above HAVE to be IDENTICAL to those below */
|
||||
@ -56,6 +58,7 @@ typedef struct ___MoSDriv {
|
||||
char *name, float newValue);
|
||||
void (*ListDriverPar) (void *self, char *motorName, SConnection * pCon);
|
||||
void (*KillPrivate) (void *self);
|
||||
int (*GetDriverTextPar) (void *self, char *name, char *textPar);
|
||||
|
||||
/* Simulation specific fields */
|
||||
float fFailure; /* percent random failures */
|
||||
|
47
motor.c
47
motor.c
@ -81,6 +81,8 @@
|
||||
#define IGNOREFAULT 10
|
||||
#define MOVECOUNT 11
|
||||
|
||||
extern double DoubleTime(void);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static void SetMotorError(pMotor self, char *text)
|
||||
{
|
||||
@ -351,8 +353,9 @@ static int checkPosition(pMotor self, SConnection * pCon)
|
||||
SCWrite(pCon, pBueffel, eWarning);
|
||||
return HWFault;
|
||||
}
|
||||
snprintf(pBueffel, 131, "WARNING: %s off position by %f",
|
||||
self->name, absf(fHard - self->fTarget));
|
||||
snprintf(pBueffel, 131, "WARNING: %s off position by %f%s",
|
||||
self->name, absf(fHard - self->fTarget),
|
||||
self->fTarget > fHard ? "-" : "");
|
||||
SCWrite(pCon, pBueffel, eLog);
|
||||
status = statusRunTo(self, pCon);
|
||||
return status;
|
||||
@ -361,16 +364,19 @@ static int checkPosition(pMotor self, SConnection * pCon)
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
static void finishDriving(pMotor self, SConnection * pCon)
|
||||
void finishDriving(pMotor self, SConnection * pCon)
|
||||
{
|
||||
MotCallback sCall;
|
||||
MotorGetSoftPosition(self, pCon, &sCall.fVal);
|
||||
sCall.pName = self->name;
|
||||
self->fPosition = sCall.fVal;
|
||||
self->fPosition = sCall.fVal;
|
||||
InvokeCallBack(self->pCall, MOTDRIVE, &sCall); /* send also very last position */
|
||||
InvokeCallBack(self->pCall, MOTEND, &sCall);
|
||||
tracePar(self->name,"%f",sCall.fVal);
|
||||
if (self->moving) {
|
||||
InvokeCallBack(self->pCall, MOTDRIVE, &sCall); /* send also very last position */
|
||||
InvokeCallBack(self->pCall, MOTEND, &sCall);
|
||||
tracePar(self->name,"%f",sCall.fVal);
|
||||
}
|
||||
self->moving = 0;
|
||||
self->running = 0;
|
||||
}
|
||||
|
||||
@ -474,13 +480,15 @@ static void handleMoveCallback(pMotor self, SConnection * pCon)
|
||||
{
|
||||
MotCallback sCall;
|
||||
|
||||
self->posCount++;
|
||||
if (self->posCount >= ObVal(self->ParArray, MOVECOUNT)) {
|
||||
double current_time, skip_time;
|
||||
current_time = DoubleTime();
|
||||
skip_time = 0.001 * ObVal(self->ParArray,MOVECOUNT);
|
||||
if(self->last_report_time + skip_time <= current_time) {
|
||||
MotorGetSoftPosition(self, pCon, &sCall.fVal);
|
||||
sCall.pName = self->name;
|
||||
InvokeCallBack(self->pCall, MOTDRIVE, &sCall);
|
||||
tracePar(self->name,"%f",sCall.fVal);
|
||||
self->posCount = 0;
|
||||
self->last_report_time = current_time;
|
||||
}
|
||||
}
|
||||
|
||||
@ -749,8 +757,10 @@ static long MotorRunImpl(void *sulf, SConnection * pCon, float fNew)
|
||||
self->posFaultCount = 0;
|
||||
self->retryCount = 0;
|
||||
self->stopped = 0;
|
||||
self->moving = 1;
|
||||
self->fTarget = fHard;
|
||||
InvokeCallBack(self->pCall, HDBVAL, self);
|
||||
self->last_report_time = 0.0;
|
||||
self->posCount = 0;
|
||||
iRet = self->pDriver->RunTo(self->pDriver, fHard);
|
||||
if (iRet != OKOK) { /* try three times to fix it */
|
||||
@ -824,7 +834,7 @@ pMotor MotorInit(char *drivername, char *name, MotorDriver * pDriv)
|
||||
ObParInit(pM->ParArray, ECOUNT, "failafter", 3.0, usMugger);
|
||||
ObParInit(pM->ParArray, POSCOUNT, "maxretry", 3.0, usMugger);
|
||||
ObParInit(pM->ParArray, IGNOREFAULT, "ignorefault", 0.0, usMugger);
|
||||
ObParInit(pM->ParArray, MOVECOUNT, "movecount", 10.0, usMugger);
|
||||
ObParInit(pM->ParArray, MOVECOUNT, "movecount", 500.0, usMugger);
|
||||
pDriv->GetPosition(pDriv, &(pM->fPosition));
|
||||
pM->fTarget = pM->fPosition;
|
||||
pM->endScriptID = 0;
|
||||
@ -1210,6 +1220,20 @@ static int EndScriptCallback(int iEvent, void *pEvent, void *pUser)
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/*
|
||||
* Context test function for callback removal
|
||||
*/
|
||||
int CheckMotiMatch(const void* context, const void* pUserData)
|
||||
{
|
||||
pMotInfo pMoti = (pMotInfo) pUserData;
|
||||
SConnection *pCon = (SConnection*) context;
|
||||
if (VerifyConnection(pCon) && VerifyConnection(pMoti->pCon)) {
|
||||
if (pMoti->pCon->ident == pCon->ident)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
The wrapper function for a motor. Commands currently supported are:
|
||||
|
||||
@ -1305,13 +1329,14 @@ int MotorAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
}
|
||||
pMoti->lastValue = fValue;
|
||||
|
||||
RemoveCallbackUsr(self->pCall, InterestCallback, CheckMotiMatch, pCon); /* only this one */
|
||||
lID = RegisterCallback(self->pCall, MOTDRIVE, InterestCallback,
|
||||
pMoti, KillInfo);
|
||||
DeleteTokenList(pList);
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
} else if (strcmp(pCurrent->text, "uninterest") == 0) {
|
||||
RemoveCallbackCon(self->pCall, pCon);
|
||||
RemoveCallbackUsr(self->pCall, InterestCallback, CheckMotiMatch, pCon); /* only this one */
|
||||
SCSendOK(pCon);
|
||||
DeleteTokenList(pList);
|
||||
return 1;
|
||||
|
3
motor.h
3
motor.h
@ -41,6 +41,9 @@ typedef struct __Motor {
|
||||
int stopReported;
|
||||
int errorCount;
|
||||
int running;
|
||||
int moving;
|
||||
double last_report_time;
|
||||
ObjectFunc pActionRoutine;
|
||||
ObPar *ParArray;
|
||||
void *pPrivate;
|
||||
void (*KillPrivate) (void *);
|
||||
|
@ -298,7 +298,7 @@ static int SecMotorStatus(void *sulf, SConnection * pCon)
|
||||
int status;
|
||||
pHdb node = NULL;
|
||||
hdbValue v;
|
||||
float interrupt;
|
||||
float interrupt = 0.;
|
||||
char error[132];
|
||||
|
||||
assert(sulf);
|
||||
@ -350,7 +350,7 @@ static int SecMotorStatus(void *sulf, SConnection * pCon)
|
||||
case HWFault:
|
||||
self->posCount = 10000;
|
||||
handleMoveCallback(self, pCon);
|
||||
SecMotorGetPar(self, "interrupt", &interrupt);
|
||||
SecMotorGetPar(self, "interruptmode", &interrupt);
|
||||
if (SCGetInterrupt(pCon) < (int) interrupt) {
|
||||
SCSetInterrupt(pCon, (int) interrupt);
|
||||
}
|
||||
@ -527,7 +527,7 @@ static hdbCallbackReturn SecMotorCallback(pHdb node, void *userData,
|
||||
SCSetInterrupt(pCon, eAbortBatch);
|
||||
self->pDrivInt->iErrorCount = 0;
|
||||
child = GetHipadabaNode(self->pDescriptor->parNode, "status");
|
||||
UpdateHipadabaPar(child, MakeHdbText("run"), pCon);
|
||||
UpdateHipadabaPar(child, MakeHdbText("error"), pCon);
|
||||
return hdbAbort;
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,14 @@
|
||||
|
||||
#define MAXSLAVE 16
|
||||
#define NOCOUNTERS -2727
|
||||
|
||||
/*
|
||||
checkSlaves codes
|
||||
*/
|
||||
#define WAITMASTER 100
|
||||
#define WAITSLAVE 200
|
||||
#define FINISHED 300
|
||||
|
||||
/*=============== code for the driver ======================================*/
|
||||
typedef struct {
|
||||
void *slaveData[MAXSLAVE];
|
||||
@ -107,7 +115,7 @@ static int MMCCStart(void *pData, SConnection * pCon)
|
||||
pCount->isUpToDate = 0;
|
||||
pCount->tStart = time(NULL);
|
||||
InvokeCallBack(pCount->pCall, COUNTSTART, pCon);
|
||||
self->checkSlaves = 0;
|
||||
self->checkSlaves = WAITMASTER;
|
||||
return OKOK;
|
||||
}
|
||||
|
||||
@ -115,7 +123,7 @@ static int MMCCStart(void *pData, SConnection * pCon)
|
||||
|
||||
static int MMCCStatus(void *pData, SConnection * pCon)
|
||||
{
|
||||
int status, i;
|
||||
int status = HWIdle, i;
|
||||
pCounter pCount = NULL, pMaster = NULL;;
|
||||
pMultiCounter self = NULL;
|
||||
pDummy pDum = NULL;
|
||||
@ -132,7 +140,7 @@ static int MMCCStatus(void *pData, SConnection * pCon)
|
||||
return HWFault;
|
||||
}
|
||||
|
||||
if(self->checkSlaves == 0) {
|
||||
if(self->checkSlaves == WAITMASTER) {
|
||||
status = self->slaves[0]->CheckCountStatus(self->slaveData[0], pCon);
|
||||
if (status == HWIdle || status == HWFault) {
|
||||
/*
|
||||
@ -141,11 +149,11 @@ static int MMCCStatus(void *pData, SConnection * pCon)
|
||||
*/
|
||||
MMCCHalt(pData);
|
||||
ReleaseCountLock(pCount->pCountInt);
|
||||
self->checkSlaves = 1;
|
||||
self->checkSlaves = WAITSLAVE;
|
||||
status = HWBusy;
|
||||
}
|
||||
pCount->pDriv->fLastCurrent = GetControlValue(self->slaveData[0]);
|
||||
} else {
|
||||
} else if(self->checkSlaves == WAITSLAVE) {
|
||||
/*
|
||||
* wait for the detectors to report finish too. Otherwise, with the second
|
||||
* generation HM data may not be fully transferred.
|
||||
@ -172,7 +180,9 @@ static int MMCCStatus(void *pData, SConnection * pCon)
|
||||
}
|
||||
status = HWIdle;
|
||||
InvokeCallBack(pCount->pCall, COUNTEND, pCon);
|
||||
self->checkSlaves = 0;
|
||||
self->checkSlaves = FINISHED;
|
||||
} else if(self->checkSlaves == FINISHED){
|
||||
status = HWIdle;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@ -530,6 +540,7 @@ int MakeMultiCounter(SConnection * pCon, SicsInterp * pSics,
|
||||
self->slaveData[self->nSlaves] = pCom->pData;
|
||||
self->nSlaves++;
|
||||
}
|
||||
self->checkSlaves = FINISHED;
|
||||
|
||||
/*
|
||||
now install our action command and we are done
|
||||
|
2
mumo.c
2
mumo.c
@ -396,7 +396,7 @@ static int ParseAlias(psParser pParse, SConnection * pCon, pMulMot self)
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
snprintf(pBueffel,1024, "ERROR: Unexpected symbol %s", pParse->Token);
|
||||
snprintf(pBueffel,sizeof(pBueffel), "ERROR: Unexpected symbol %s", pParse->Token);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
|
4
napiu.c
4
napiu.c
@ -21,10 +21,10 @@
|
||||
|
||||
For further information, see <http://www.nexus.anl.gov/>
|
||||
|
||||
$Id: napiu.c,v 1.4 2012/03/29 08:41:06 koennecke Exp $
|
||||
$Id$
|
||||
|
||||
----------------------------------------------------------------------------*/
|
||||
static const char* rscid = "$Id: napiu.c,v 1.4 2012/03/29 08:41:06 koennecke Exp $"; /* Revision interted by CVS */
|
||||
static const char* rscid = "$Id$"; /* Revision interted by CVS */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
2
napiu.h
2
napiu.h
@ -21,7 +21,7 @@
|
||||
|
||||
For further information, see <http://www.nexus.anl.gov/>
|
||||
|
||||
$Id: napiu.h,v 1.3 2009/02/13 09:00:20 koennecke Exp $
|
||||
$Id$
|
||||
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
|
29
network.c
29
network.c
@ -188,7 +188,7 @@ mkChannel *NETAccept(mkChannel * self, long timeout)
|
||||
return NULL; /* eof */
|
||||
}
|
||||
iRet =
|
||||
uselect((self->sockid + 1), (fd_set *) & lMask, NULL, NULL, &tmo);
|
||||
uselect((self->sockid + 1), &lMask, NULL, NULL, &tmo);
|
||||
if (iRet <= 0) {
|
||||
/* failure, or no request */
|
||||
return NULL;
|
||||
@ -327,7 +327,7 @@ int NETConnectFinished(mkChannel * self)
|
||||
return -1;
|
||||
}
|
||||
oldopts = fcntl(self->sockid, F_GETFL, 0);
|
||||
if (!(oldopts | O_NONBLOCK)) {
|
||||
if (!(oldopts & O_NONBLOCK)) { /* DCL was | */
|
||||
/* assume success when in blocking mode */
|
||||
return 1;
|
||||
}
|
||||
@ -360,7 +360,7 @@ int NETConnectFinished(mkChannel * self)
|
||||
}
|
||||
/* reset to blocking mode */
|
||||
olderrno = errno;
|
||||
fcntl(self->sockid, F_SETFL, oldopts | ~O_NONBLOCK);
|
||||
fcntl(self->sockid, F_SETFL, oldopts & ~O_NONBLOCK); /* DCL was | */
|
||||
errno = olderrno;
|
||||
return iret;
|
||||
}
|
||||
@ -679,7 +679,7 @@ int NETReadTillTerm(mkChannel * self, long timeout,
|
||||
status = NETAvailable(self, timeout - dif);
|
||||
};
|
||||
};
|
||||
return status;
|
||||
return bufPtr;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -753,14 +753,20 @@ int NETReconnectWithFlags(mkChannel * self, int flags)
|
||||
if (self->sockid != 0) {
|
||||
close(self->sockid);
|
||||
}
|
||||
/* Reopen and try to get it on the olf fd */
|
||||
/* Reopen and try to get it on the old fd */
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
/* If this isn't the same fd, try to move it over */
|
||||
if (self->sockid != sock) {
|
||||
/* Duplicate the new socket with the old fd if we can */
|
||||
iRet = fcntl(sock, F_DUPFD, self->sockid);
|
||||
if (iRet != sock)
|
||||
if (iRet != self->sockid) {
|
||||
/* If we didn't get the one we want, use original and close new */
|
||||
self->sockid = sock;
|
||||
else
|
||||
close(iRet);
|
||||
} else {
|
||||
/* If we did get the one we want, close original and use old */
|
||||
close(sock);
|
||||
}
|
||||
sock = self->sockid;
|
||||
}
|
||||
/* restore the old flags */
|
||||
@ -798,7 +804,7 @@ int NETReconnectWithFlags(mkChannel * self, int flags)
|
||||
if (iRet <= 0)
|
||||
iRet = -1; /* failure */
|
||||
}
|
||||
if (FD_ISSET(self->sockid, &wmask)) {
|
||||
else if (FD_ISSET(self->sockid, &wmask)) {
|
||||
iRet = send(self->sockid, NULL, 0, 0);
|
||||
if (iRet < 0)
|
||||
iRet = -1; /* failure */
|
||||
@ -920,7 +926,7 @@ mkChannel *UDPConnect(char *name, int port)
|
||||
/*--------------------------------------------------------------------------*/
|
||||
long UDPRead(mkChannel * self, char *buffer, long lLen, int timeout)
|
||||
{
|
||||
long lMask = 0L;
|
||||
fd_set lMask;
|
||||
struct timeval tmo = { 0, 1 };
|
||||
long iRet;
|
||||
socklen_t iLang;
|
||||
@ -934,9 +940,10 @@ long UDPRead(mkChannel * self, char *buffer, long lLen, int timeout)
|
||||
/* setup for select first */
|
||||
tmo.tv_usec = (timeout % 1000) * 1000;
|
||||
tmo.tv_sec = timeout / 1000;
|
||||
lMask = (1 << self->sockid);
|
||||
FD_ZERO(&lMask);
|
||||
FD_SET(self->sockid, &lMask);
|
||||
iRet =
|
||||
uselect((self->sockid + 1), (fd_set *) & lMask, NULL, NULL, &tmo);
|
||||
uselect((self->sockid + 1), &lMask, NULL, NULL, &tmo);
|
||||
if (iRet <= 0) {
|
||||
/* failure, or no data */
|
||||
return 0;
|
||||
|
42
nread.c
42
nread.c
@ -42,6 +42,8 @@
|
||||
#include "commandlog.h"
|
||||
#include "uselect.h"
|
||||
#include "trace.h"
|
||||
#include "protocol.h"
|
||||
|
||||
|
||||
extern pServer pServ;
|
||||
extern int VerifyChannel(mkChannel * self); /* defined in network.c */
|
||||
@ -294,15 +296,25 @@ static int NetReadRead(pNetRead self, pNetItem pItem)
|
||||
*pEnd = '\0';
|
||||
/* do we have something in hold ? */
|
||||
if (strlen(pItem->pHold) > 0) {
|
||||
strlcat(pItem->pHold, pPtr,511);
|
||||
iStat = CostaTop(pItem->pCon->pStack, pItem->pHold);
|
||||
strlcat(pItem->pHold, pPtr, 511);
|
||||
/* DFC locking for protocol zero only */
|
||||
if (pItem->pCon->iProtocolID == PROTSICS &&
|
||||
CostaLocked(pItem->pCon->pStack))
|
||||
iStat = 0;
|
||||
else
|
||||
iStat = CostaTop(pItem->pCon->pStack, pItem->pHold);
|
||||
if (!iStat) {
|
||||
SCWrite(pItem->pCon, "ERROR: Busy", eError);
|
||||
}
|
||||
pItem->pHold[0] = '\0';
|
||||
} else {
|
||||
/* no, normal command */
|
||||
iStat = CostaTop(pItem->pCon->pStack, pPtr);
|
||||
/* DFC locking for protocol zero only */
|
||||
if (pItem->pCon->iProtocolID == PROTSICS &&
|
||||
CostaLocked(pItem->pCon->pStack))
|
||||
iStat = 0;
|
||||
else
|
||||
iStat = CostaTop(pItem->pCon->pStack, pPtr);
|
||||
if (!iStat) {
|
||||
SCWrite(pItem->pCon, "ERROR: Busy", eError);
|
||||
}
|
||||
@ -487,7 +499,12 @@ static int TelnetRead(pNetRead self, pNetItem pItem)
|
||||
break;
|
||||
case '\r':
|
||||
case '\n':
|
||||
iStat = CostaTop(pItem->pCon->pStack, pItem->pHold);
|
||||
/* DFC locking for protocol zero only */
|
||||
if (pItem->pCon->iProtocolID == PROTSICS &&
|
||||
CostaLocked(pItem->pCon->pStack))
|
||||
iStat = 0;
|
||||
else
|
||||
iStat = CostaTop(pItem->pCon->pStack, pItem->pHold);
|
||||
/* printf("%s\n",pItem->pHold); */
|
||||
if (!iStat) {
|
||||
SCWrite(pItem->pCon, "ERROR: Busy", eError);
|
||||
@ -1027,6 +1044,7 @@ static int testAndInvokeInterrupt(pCommandCBData self, int handle)
|
||||
snprintf(buffer, 512, "INTERRUPT %d issued on sock %d",
|
||||
iInt, handle);
|
||||
WriteToCommandLog("SYS>", buffer);
|
||||
SICSLogWrite(buffer, eInternal);
|
||||
if (iInt == eEndServer) {
|
||||
TaskStop(pServ->pTasker);
|
||||
}
|
||||
@ -1060,8 +1078,10 @@ static int CommandDataCB(int handle, void *userData)
|
||||
if (pPtr[i] == '\r' || pPtr[i] == '\n') {
|
||||
self->state = SKIPTERM;
|
||||
if (!testAndInvokeInterrupt(self, handle)) {
|
||||
status =
|
||||
CostaTop(self->pCon->pStack, GetCharArray(self->command));
|
||||
if (self->pCon->iProtocolID == PROTSICS && CostaLocked(self->pCon->pStack))
|
||||
status = 0;
|
||||
else
|
||||
status = CostaTop(self->pCon->pStack, GetCharArray(self->command));
|
||||
if (!status) {
|
||||
SCWrite(self->pCon, "ERROR: Busy", eError);
|
||||
}
|
||||
@ -1162,8 +1182,10 @@ static int ANETTelnetProcess(int handle, void *usData)
|
||||
case '\r':
|
||||
case '\n':
|
||||
if (!testAndInvokeInterrupt(self, handle)) {
|
||||
status =
|
||||
CostaTop(self->pCon->pStack, GetCharArray(self->command));
|
||||
if (self->pCon->iProtocolID == PROTSICS && CostaLocked(self->pCon->pStack))
|
||||
status = 0;
|
||||
else
|
||||
status = CostaTop(self->pCon->pStack, GetCharArray(self->command));
|
||||
if (!status) {
|
||||
SCWrite(self->pCon, "ERROR: Busy", eError);
|
||||
}
|
||||
@ -1333,8 +1355,8 @@ static int TelnetAcceptCB(int handle, void *userData)
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
static void NREADlog(int level, char *txt, void *userData)
|
||||
{
|
||||
traceSys("anet",txt);
|
||||
puts(txt);
|
||||
traceSys("anet","%s",txt);
|
||||
SICSLogWrite(txt, (level == ANETERROR) ? eLogError : eLog);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------*/
|
||||
|
34
nserver.c
34
nserver.c
@ -40,12 +40,16 @@
|
||||
#include "commandlog.h"
|
||||
|
||||
|
||||
extern void StopExit(void); /* in SICSmain.c */
|
||||
|
||||
extern int openDevexecLog(); /* in devexec.c */
|
||||
|
||||
extern void NetWatchInit(void); /* in nwatch.c */
|
||||
/* ========================= Less dreadful file statics =================== */
|
||||
extern int NetWatchTask(void *pData); /* in nwatch.c */
|
||||
/*------------------------------------------------------------------------*/
|
||||
static void StopExit(void)
|
||||
{
|
||||
if (pServ) {
|
||||
StopServer(pServ);
|
||||
}
|
||||
}
|
||||
|
||||
#define DEFAULTINIFILE "servo.tcl"
|
||||
#define DEFAULTSTATUSFILE "sicsstat.tcl"
|
||||
@ -116,7 +120,7 @@ int InitServer(char *file, pServer * pServ)
|
||||
pSICSOptions = IFAddOption(pSICSOptions, "ConMask", "0");
|
||||
|
||||
/* initialize the network watcher */
|
||||
NetWatchInit();
|
||||
TaskRegister(self->pTasker, NetWatchTask, NULL, NULL, NULL, 1);
|
||||
|
||||
/* initialise the server from script */
|
||||
SetWriteHistory(0);
|
||||
@ -507,3 +511,23 @@ int ServerIsStarting(pServer self)
|
||||
{
|
||||
return self->pReader == NULL;
|
||||
}
|
||||
|
||||
pServer pServ = NULL;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
SicsInterp *GetInterpreter(void)
|
||||
{
|
||||
return pServ->pSics;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
pExeList GetExecutor(void)
|
||||
{
|
||||
return pServ->pExecutor;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
pTaskMan GetTasker(void)
|
||||
{
|
||||
return pServ->pTasker;
|
||||
}
|
||||
|
114
nwatch.c
114
nwatch.c
@ -18,8 +18,8 @@
|
||||
#include <sys/time.h>
|
||||
#include "fortify.h"
|
||||
#include "nwatch.h"
|
||||
#include "sics.h"
|
||||
#include "uselect.h"
|
||||
#include "sics.h"
|
||||
|
||||
#define NWMAGIC 51966
|
||||
|
||||
@ -36,14 +36,12 @@ typedef struct __netwatcher_s {
|
||||
/* Singleton pattern */
|
||||
static pNetWatch instance = NULL;
|
||||
|
||||
static int NetWatchTask(void *pData);
|
||||
|
||||
/**
|
||||
* \brief Initialises the Net Watcher singleton and starts the task
|
||||
*
|
||||
* \return 1=success, 0=failure
|
||||
*/
|
||||
int NetWatchInit(void)
|
||||
static pNetWatch NetWatchGetInstance(void)
|
||||
{
|
||||
/*
|
||||
* If the singleton has not yet been created, do so now
|
||||
@ -54,9 +52,8 @@ int NetWatchInit(void)
|
||||
return 0;
|
||||
memset(instance, 0, sizeof(NetWatch));
|
||||
instance->lMagic = NWMAGIC;
|
||||
TaskRegisterN(pServ->pTasker,"nwatch", NetWatchTask, NULL, NULL, NULL, 1);
|
||||
}
|
||||
return 1;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -67,10 +64,13 @@ typedef struct __netwatchtimer {
|
||||
struct timeval tv; /* time when event is due */
|
||||
pNWCallback func; /* function to call */
|
||||
void *cntx; /* abstract context to pass to callback */
|
||||
long int tick; /* millisecond repeat rate */
|
||||
int msec; /* millisecond delay time */
|
||||
int tick; /* millisecond repeat rate */
|
||||
long int vrfy; /* integrity check */
|
||||
} NWTimer;
|
||||
|
||||
static pNWTimer activeTimer = NULL;
|
||||
|
||||
/*
|
||||
* \brief private function to insert an entry into the sorted timer queue.
|
||||
*
|
||||
@ -83,6 +83,7 @@ static int NetWatchTimerInsQue(pNetWatch self, pNWTimer handle)
|
||||
if (self->tq_head == NULL) {
|
||||
self->tq_head = self->tq_tail = handle;
|
||||
handle->next = NULL;
|
||||
handle->vrfy = NWMAGIC;
|
||||
return 1;
|
||||
}
|
||||
/* if new one is not earlier than latest one, insert after latest */
|
||||
@ -92,6 +93,7 @@ static int NetWatchTimerInsQue(pNetWatch self, pNWTimer handle)
|
||||
self->tq_tail->next = handle;
|
||||
self->tq_tail = handle;
|
||||
handle->next = NULL;
|
||||
handle->vrfy = NWMAGIC;
|
||||
return 1;
|
||||
}
|
||||
/* if new one is not later than earliest one, insert before earliest */
|
||||
@ -100,6 +102,7 @@ static int NetWatchTimerInsQue(pNetWatch self, pNWTimer handle)
|
||||
handle->tv.tv_usec <= self->tq_head->tv.tv_usec)) {
|
||||
handle->next = self->tq_head;
|
||||
self->tq_head = handle;
|
||||
handle->vrfy = NWMAGIC;
|
||||
return 1;
|
||||
} else {
|
||||
/* must be in between two so start at the first entry */
|
||||
@ -113,8 +116,10 @@ static int NetWatchTimerInsQue(pNetWatch self, pNWTimer handle)
|
||||
/* slip new one in between this one and the next one */
|
||||
handle->next = pNxt->next;
|
||||
pNxt->next = handle;
|
||||
handle->vrfy = NWMAGIC;
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -125,6 +130,7 @@ static int NetWatchTimerInsQue(pNetWatch self, pNWTimer handle)
|
||||
*/
|
||||
static int NetWatchTimerRemQue(pNetWatch self, pNWTimer handle)
|
||||
{
|
||||
assert(handle->vrfy == NWMAGIC);
|
||||
/* handle the case of first and possibly only */
|
||||
if (handle == self->tq_head) {
|
||||
self->tq_head = self->tq_head->next; /* may be NULL */
|
||||
@ -145,13 +151,15 @@ static int NetWatchTimerRemQue(pNetWatch self, pNWTimer handle)
|
||||
if (handle == self->tq_tail)
|
||||
self->tq_tail = pNxt;
|
||||
}
|
||||
handle->vrfy = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int NetWatchRegisterTimer(pNWTimer * handle, int mSec,
|
||||
pNWCallback callback, void *context)
|
||||
{
|
||||
pNetWatch self = instance;
|
||||
assert(callback);
|
||||
pNetWatch self = NetWatchGetInstance();
|
||||
if (!self || self->lMagic != NWMAGIC)
|
||||
return 0;
|
||||
pNWTimer pNew = (pNWTimer) malloc(sizeof(NWTimer));
|
||||
@ -165,10 +173,10 @@ int NetWatchRegisterTimer(pNWTimer * handle, int mSec,
|
||||
pNew->tv.tv_sec++;
|
||||
pNew->tv.tv_usec -= 1000000;
|
||||
}
|
||||
pNew->msec = mSec;
|
||||
pNew->tick = 0;
|
||||
pNew->func = callback;
|
||||
pNew->cntx = context;
|
||||
pNew->vrfy = NWMAGIC;
|
||||
NetWatchTimerInsQue(self, pNew);
|
||||
*handle = pNew;
|
||||
return 1;
|
||||
@ -178,6 +186,7 @@ int NetWatchRegisterTimerPeriodic(pNWTimer * handle, int mSecInitial,
|
||||
int mSecPeriod, pNWCallback callback,
|
||||
void *context)
|
||||
{
|
||||
assert(callback);
|
||||
if (NetWatchRegisterTimer(handle, mSecInitial, callback, context)) {
|
||||
pNWTimer pNew = *handle;
|
||||
if (pNew == NULL)
|
||||
@ -189,16 +198,36 @@ int NetWatchRegisterTimerPeriodic(pNWTimer * handle, int mSecInitial,
|
||||
return 0;
|
||||
}
|
||||
|
||||
pNWTimer NetWatchGetActiveTimer(void)
|
||||
{
|
||||
return activeTimer;
|
||||
}
|
||||
|
||||
int NetWatchGetTimerInitial(pNWTimer handle)
|
||||
{
|
||||
if (handle == NULL
|
||||
|| (handle->vrfy != NWMAGIC && handle->vrfy != ~NWMAGIC))
|
||||
return 0;
|
||||
return handle->msec;
|
||||
}
|
||||
|
||||
int NetWatchGetTimerDelay(pNWTimer handle)
|
||||
{
|
||||
return NetWatchGetTimerInitial(handle);
|
||||
}
|
||||
|
||||
int NetWatchGetTimerPeriod(pNWTimer handle)
|
||||
{
|
||||
if (handle == NULL || handle->vrfy != NWMAGIC)
|
||||
if (handle == NULL
|
||||
|| (handle->vrfy != NWMAGIC && handle->vrfy != ~NWMAGIC))
|
||||
return 0;
|
||||
return handle->tick;
|
||||
}
|
||||
|
||||
int NetWatchSetTimerPeriod(pNWTimer handle, int mSecPeriod)
|
||||
{
|
||||
if (handle == NULL || handle->vrfy != NWMAGIC)
|
||||
if (handle == NULL
|
||||
|| (handle->vrfy != NWMAGIC && handle->vrfy != ~NWMAGIC))
|
||||
return 0;
|
||||
handle->tick = mSecPeriod;
|
||||
return 1;
|
||||
@ -206,9 +235,11 @@ int NetWatchSetTimerPeriod(pNWTimer handle, int mSecPeriod)
|
||||
|
||||
int NetWatchRemoveTimer(pNWTimer handle)
|
||||
{
|
||||
pNetWatch self = instance;
|
||||
pNetWatch self = NetWatchGetInstance();
|
||||
if (!self || self->lMagic != NWMAGIC)
|
||||
return 0;
|
||||
if (handle == NULL || handle->vrfy != NWMAGIC)
|
||||
return 0;
|
||||
NetWatchTimerRemQue(self, handle);
|
||||
handle->vrfy = 0;
|
||||
free(handle);
|
||||
@ -239,35 +270,10 @@ static int NetWatchContextInsQue(pNetWatch self, pNWContext handle)
|
||||
self->cq_tail->next = handle;
|
||||
self->cq_tail = handle;
|
||||
}
|
||||
handle->vrfy = NWMAGIC;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief private function to remove entry from unsorted queue
|
||||
*
|
||||
* \param self singleton
|
||||
* \param handle entry to insert
|
||||
*/
|
||||
static void NetWatchContextRemQue(pNetWatch self, pNWContext handle)
|
||||
{
|
||||
if (handle == self->cq_head) { /* if first */
|
||||
self->cq_head = self->cq_head->next;
|
||||
if (handle == self->cq_tail) /* if also last */
|
||||
self->cq_tail = NULL;
|
||||
} else {
|
||||
pNWContext pNxt = self->cq_head;
|
||||
while (pNxt) {
|
||||
if (handle == pNxt->next) {
|
||||
pNxt->next = pNxt->next->next;
|
||||
break;
|
||||
}
|
||||
pNxt = pNxt->next;
|
||||
}
|
||||
if (handle == self->cq_tail) /* if last */
|
||||
self->cq_tail = pNxt;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief private function to purge invalid entries
|
||||
@ -286,19 +292,19 @@ static void NetWatchContextPrgQue(pNetWatch self)
|
||||
free(tmp);
|
||||
}
|
||||
pNxt = self->cq_head;
|
||||
while (pNxt) {
|
||||
if (pNxt->next && pNxt->next->sock < 0) {
|
||||
while (pNxt && pNxt->next) {
|
||||
if (pNxt->next->sock < 0) {
|
||||
pNWContext tmp = NULL;
|
||||
tmp = pNxt->next;
|
||||
pNxt->next = pNxt->next->next;
|
||||
tmp->vrfy = 0;
|
||||
free(tmp);
|
||||
continue;
|
||||
}
|
||||
pNxt = pNxt->next;
|
||||
}
|
||||
/* if the queue is empty clear the tail */
|
||||
if (self->cq_head == NULL)
|
||||
self->cq_tail = pNxt;
|
||||
/* if the queue is empty then pNxt is NULL else pNxt points to the tail */
|
||||
self->cq_tail = pNxt;
|
||||
self->nInvalid = 0;
|
||||
return;
|
||||
}
|
||||
@ -306,8 +312,9 @@ static void NetWatchContextPrgQue(pNetWatch self)
|
||||
int NetWatchRegisterCallback(pNWContext * handle, int iSocket,
|
||||
pNWCallback callback, void *context)
|
||||
{
|
||||
assert(callback);
|
||||
pNWContext pNew = NULL;
|
||||
pNetWatch self = instance;
|
||||
pNetWatch self = NetWatchGetInstance();
|
||||
if (!self || self->lMagic != NWMAGIC)
|
||||
return 0;
|
||||
if (iSocket < 0 || iSocket > 65535)
|
||||
@ -320,7 +327,6 @@ int NetWatchRegisterCallback(pNWContext * handle, int iSocket,
|
||||
pNew->mode = nwatch_read;
|
||||
pNew->func = callback;
|
||||
pNew->cntx = context;
|
||||
pNew->vrfy = NWMAGIC;
|
||||
*handle = pNew;
|
||||
NetWatchContextInsQue(self, pNew);
|
||||
return 1;
|
||||
@ -328,13 +334,16 @@ int NetWatchRegisterCallback(pNWContext * handle, int iSocket,
|
||||
|
||||
int NetWatchRemoveCallback(pNWContext handle)
|
||||
{
|
||||
pNetWatch self = instance;
|
||||
pNetWatch self = NetWatchGetInstance();
|
||||
if (handle == NULL || handle->vrfy != NWMAGIC)
|
||||
return 0;
|
||||
if (!self || self->lMagic != NWMAGIC)
|
||||
return 0;
|
||||
/* mark as invalid */
|
||||
handle->sock = -1;
|
||||
/* increment count of invalid */
|
||||
self->nInvalid++;
|
||||
/* leave for garbage collection */
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -354,7 +363,8 @@ int NetWatchSetMode(pNWContext handle, int mode)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief the registered SICS Task to drive all this
|
||||
* \brief the task to drive all this
|
||||
* Should be called periodically
|
||||
*/
|
||||
int NetWatchTask(void *pData)
|
||||
{
|
||||
@ -367,7 +377,7 @@ int NetWatchTask(void *pData)
|
||||
int iCount;
|
||||
|
||||
/* Check the singleton */
|
||||
self = (pNetWatch) instance;
|
||||
self = NetWatchGetInstance();
|
||||
if (!self || self->lMagic != NWMAGIC)
|
||||
return 0;
|
||||
|
||||
@ -375,7 +385,7 @@ int NetWatchTask(void *pData)
|
||||
if (self->nInvalid > 0)
|
||||
NetWatchContextPrgQue(self);
|
||||
|
||||
/* build the select mask */
|
||||
/* build the select mask */
|
||||
FD_ZERO(&rMask);
|
||||
FD_ZERO(&wMask);
|
||||
pNWC = self->cq_head;
|
||||
@ -430,7 +440,11 @@ int NetWatchTask(void *pData)
|
||||
break;
|
||||
}
|
||||
NetWatchTimerRemQue(self, pNew);
|
||||
activeTimer = pNew;
|
||||
activeTimer->vrfy = ~NWMAGIC;
|
||||
iStatus = pNew->func(pNew->cntx, 0);
|
||||
activeTimer->vrfy = 0;
|
||||
activeTimer = NULL;
|
||||
/*
|
||||
* If this is a recurrent timer and the function
|
||||
* indicates to keep it going, put it back in
|
||||
|
12
nwatch.h
12
nwatch.h
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* N E T W A T C H E R
|
||||
* N E T W A T C H
|
||||
*
|
||||
* This module watches network connections for sockets becoming readable or
|
||||
* writeable and invokes callbacks. It also provides a timer mechanism.
|
||||
@ -7,8 +7,8 @@
|
||||
* Douglas Clowes, February 2007
|
||||
*
|
||||
*/
|
||||
#ifndef SICSNETWATCHER
|
||||
#define SICSNETWATCHER
|
||||
#ifndef NETWATCH_H
|
||||
#define NETWATCH_H
|
||||
|
||||
#define nwatch_read 1
|
||||
#define nwatch_write 2
|
||||
@ -53,6 +53,10 @@ int NetWatchRegisterTimerPeriodic(pNWTimer * handle, int mSecInitial,
|
||||
int mSecPeriod, pNWCallback callback,
|
||||
void *context);
|
||||
|
||||
pNWTimer NetWatchGetActiveTimer(void);
|
||||
|
||||
int NetWatchGetTimerDelay(pNWTimer handle);
|
||||
int NetWatchGetTimerInitial(pNWTimer handle);
|
||||
int NetWatchGetTimerPeriod(pNWTimer handle);
|
||||
int NetWatchSetTimerPeriod(pNWTimer handle, int mSecPeriod);
|
||||
/**
|
||||
@ -103,4 +107,4 @@ int NetWatchGetMode(pNWContext handle);
|
||||
*/
|
||||
int NetWatchSetMode(pNWContext handle, int mode);
|
||||
|
||||
#endif /* SICSNETWATCHER */
|
||||
#endif /* NETWATCH_H */
|
||||
|
126
nxdict.c
126
nxdict.c
@ -173,9 +173,9 @@ static void NXDIParse(char *pBuffer, pStringDict pDict)
|
||||
char *pPtr;
|
||||
int iToken;
|
||||
int iMode;
|
||||
char pAlias[132];
|
||||
char pDefinition[1024]; /* this is > 10 lines of definition */
|
||||
char pWord[132];
|
||||
char pAlias[1024];
|
||||
char pDefinition[8192]; /* this is > 10 lines of definition */
|
||||
char pWord[1024];
|
||||
|
||||
assert(pBuffer);
|
||||
assert(pDict);
|
||||
@ -1490,6 +1490,126 @@ NXstatus NXDinfoalias(NXhandle hFil, NXdict dict, char *pAlias, int *rank,
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
NXstatus NXDdefnamedlink(NXhandle hFil, NXdict dict,
|
||||
char *pTarget, char *pVictim, char *newname)
|
||||
{
|
||||
NXdict pDict;
|
||||
ParDat pParseT, pParseV;
|
||||
int iRet, i, iStat;
|
||||
NXlink sLink;
|
||||
|
||||
pDict = NXDIAssert(dict);
|
||||
|
||||
|
||||
#ifdef DEFDEBUG
|
||||
printf("Linking: %s\n", pVictim);
|
||||
printf("To: %s\n", pTarget);
|
||||
#endif
|
||||
|
||||
|
||||
/* parse Victim */
|
||||
pParseV.iMayCreate = 0;
|
||||
pParseV.pPtr = pVictim;
|
||||
pParseV.iDepth = 0;
|
||||
iRet = NXDIDefParse(hFil, pDict, &pParseV);
|
||||
if (iRet == NX_ERROR) {
|
||||
/* unwind and throw up */
|
||||
NXDIUnwind(hFil, pParseV.iDepth);
|
||||
return NX_ERROR;
|
||||
}
|
||||
/* get link data */
|
||||
if (pParseV.iTerminal == TERMSDS) {
|
||||
NXgetdataID(hFil, &sLink);
|
||||
iRet = NXclosedata(hFil);
|
||||
if (iRet != NX_OK) {
|
||||
/* unwind and throw up */
|
||||
NXDIUnwind(hFil, pParseV.iDepth);
|
||||
return NX_ERROR;
|
||||
}
|
||||
} else if (pParseV.iTerminal == TERMVG) {
|
||||
NXgetgroupID(hFil, &sLink);
|
||||
} else {
|
||||
assert(0); /* serious programming error */
|
||||
}
|
||||
/* Unwind */
|
||||
iRet = NXDIUnwind(hFil, pParseV.iDepth);
|
||||
if (iRet != NX_OK) {
|
||||
return NX_ERROR;
|
||||
}
|
||||
|
||||
/* parse Target */
|
||||
pParseT.iMayCreate = 1;
|
||||
pParseT.pPtr = pTarget;
|
||||
pParseT.iDepth = 0;
|
||||
iRet = NXDIDefParse(hFil, pDict, &pParseT);
|
||||
if (iRet == NX_ERROR) {
|
||||
/* unwind and throw up */
|
||||
NXDIUnwind(hFil, pParseT.iDepth);
|
||||
return NX_ERROR;
|
||||
}
|
||||
/* check it being a vGroup! */
|
||||
if (pParseT.iTerminal != TERMVG) {
|
||||
NXReportError("ERROR: can link only into a vGroup");
|
||||
NXDIUnwind(hFil, pParseT.iDepth);
|
||||
return NX_ERROR;
|
||||
}
|
||||
|
||||
/* link, finally */
|
||||
iRet = NXmakenamedlink(hFil, newname, &sLink);
|
||||
/* Unwind anyway */
|
||||
iStat = NXDIUnwind(hFil, pParseT.iDepth);
|
||||
if (iStat != NX_OK) {
|
||||
return NX_ERROR;
|
||||
}
|
||||
return iStat;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
NXstatus NXDaliasnamedlink(NXhandle hFil, NXdict dict,
|
||||
char *pTarget, char *pVictim, char *newname)
|
||||
{
|
||||
char pTargetDef[2048], pVictimDef[2048];
|
||||
int iRet;
|
||||
NXdict pDict;
|
||||
pDynString pRep1 = NULL, pRep2 = NULL;
|
||||
|
||||
pDict = NXDIAssert(dict);
|
||||
|
||||
/* get Target Definition String */
|
||||
iRet = NXDget(pDict, pTarget, pTargetDef, 2047);
|
||||
if (iRet != NX_OK) {
|
||||
sprintf(pTargetDef, "ERROR: alias %s not recognized", pTarget);
|
||||
NXReportError(pTargetDef);
|
||||
return NX_ERROR;
|
||||
}
|
||||
|
||||
/* get Victim definition string */
|
||||
iRet = NXDget(pDict, pVictim, pVictimDef, 2047);
|
||||
if (iRet != NX_OK) {
|
||||
sprintf(pTargetDef, "ERROR: alias %s not recognized", pTarget);
|
||||
NXReportError(pTargetDef);
|
||||
return NX_ERROR;
|
||||
}
|
||||
|
||||
/* do replacements */
|
||||
pRep1 = NXDItextreplace(dict, pTargetDef);
|
||||
pRep2 = NXDItextreplace(dict, pVictimDef);
|
||||
if ((!pRep1) || (!pRep2)) {
|
||||
if (pRep1)
|
||||
DeleteDynString(pRep1);
|
||||
if (pRep2)
|
||||
DeleteDynString(pRep2);
|
||||
return NX_ERROR;
|
||||
}
|
||||
|
||||
/* call NXdeflin */
|
||||
iRet = NXDdefnamedlink(hFil, pDict, GetCharArray(pRep1), GetCharArray(pRep2), newname);
|
||||
DeleteDynString(pRep1);
|
||||
DeleteDynString(pRep2);
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
NXstatus NXDdeflink(NXhandle hFil, NXdict dict,
|
||||
char *pTarget, char *pVictim)
|
||||
|
52
nxscript.c
52
nxscript.c
@ -462,6 +462,7 @@ static void putHdb(SConnection * pCon, SicsInterp * pSics, pNXScript self,
|
||||
hdbValue v;
|
||||
float fVal, *floatAr = NULL;
|
||||
int i;
|
||||
int start[5], size[5];
|
||||
|
||||
if (argc < 3) {
|
||||
SCWrite(pCon, "ERROR: putHdb needs at least node name", eLogError);
|
||||
@ -484,6 +485,23 @@ static void putHdb(SConnection * pCon, SicsInterp * pSics, pNXScript self,
|
||||
}
|
||||
}
|
||||
GetHipadabaPar(node, &v, pCon);
|
||||
if (argc > 3 && strcmp(argv[3], "point") == 0) {
|
||||
NXDopenalias(self->fileHandle, self->dictHandle, alias);
|
||||
start[0] = atoi(argv[4]);
|
||||
size[0] = 1;
|
||||
switch (v.dataType) {
|
||||
case HIPINT:
|
||||
NXputslab(self->fileHandle, &v.v.intValue, start, size);
|
||||
break;
|
||||
case HIPFLOAT:
|
||||
fVal = v.v.doubleValue;
|
||||
NXputslab(self->fileHandle, &fVal, start, size);
|
||||
break;
|
||||
}
|
||||
ReleaseHdbValue(&v);
|
||||
NXopenpath(self->fileHandle, "/");
|
||||
return;
|
||||
}
|
||||
switch (v.dataType) {
|
||||
case HIPNONE:
|
||||
return;
|
||||
@ -922,6 +940,7 @@ static void putHistogramMemoryChunked(SConnection * pCon,
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
#define HANUM 3
|
||||
static void putSlab(SConnection * pCon, SicsInterp * pSics, pNXScript self,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
@ -1986,6 +2005,35 @@ static void makeLink(SConnection * pCon, SicsInterp * pSics,
|
||||
SCSendOK(pCon);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
extern NXstatus NXDaliasnamedlink(NXhandle hFil, NXdict dict,
|
||||
char *pTarget, char *pVictim, char *newname);
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
static void makeNamedLink(SConnection * pCon, SicsInterp * pSics,
|
||||
pNXScript self, int argc, char *argv[])
|
||||
{
|
||||
int status;
|
||||
char pBueffel[256];
|
||||
|
||||
if (argc < 5) {
|
||||
SCWrite(pCon, "ERROR: insufficient number of arguments to makenamedlink",
|
||||
eLogError);
|
||||
return;
|
||||
}
|
||||
|
||||
status = NXDaliasnamedlink(self->fileHandle, self->dictHandle,
|
||||
argv[2], argv[3], argv[4]);
|
||||
if (status != NX_OK) {
|
||||
snprintf(pBueffel, 255, "ERROR: linking %s against %s as %s failed",
|
||||
argv[2], argv[3], argv[4]);
|
||||
SCWrite(pCon, pBueffel, eLogError);
|
||||
return;
|
||||
}
|
||||
|
||||
SCSendOK(pCon);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
static void updateDictVar(SConnection * pCon, pNXScript self, int argc,
|
||||
char *argv[])
|
||||
@ -2095,6 +2143,10 @@ int NXScriptAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
makeLink(pCon, pSics, self, argc, argv);
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(argv[1], "makenamedlink") == 0) {
|
||||
makeNamedLink(pCon, pSics, self, argc, argv);
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
4
obpar.c
4
obpar.c
@ -176,7 +176,9 @@ int ObParSet(ObPar * self, char *obname, char *name, float fVal,
|
||||
|
||||
/* are we running? */
|
||||
if(DevExecLevelRunning(pServ->pExecutor, RUNDRIVE)){
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: Cannot change parameter while running");
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1,
|
||||
"ERROR: Cannot change %s.%s parameter while running",
|
||||
obname, name);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
|
9
ofac.c
9
ofac.c
@ -16,8 +16,11 @@
|
||||
#include "statusfile.h"
|
||||
#include "site.h"
|
||||
#include "sicshipadaba.h"
|
||||
#include "sicsglobal.h"
|
||||
|
||||
static unsigned int killStartupCommands = 1;
|
||||
int isDuringInitialization;
|
||||
|
||||
|
||||
extern void DevExecInit(void); /* devexec.c */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@ -93,6 +96,8 @@ static void InitIniCommands(SicsInterp * pInter)
|
||||
PCMD("InternEval", InternalFileEval);
|
||||
PCMD("kill_command", SICSKill);
|
||||
PCMD("list", SicsList);
|
||||
PCMD("MakeAsyncProtocol", AsyncProtocolFactory);
|
||||
PCMD("MakeAsyncQueue", AsyncQueueFactory);
|
||||
PCMD("MakeMcStasController", McStasControllerFactory);
|
||||
PCMD("MakeMulti", MakeMulti);
|
||||
PCMD("MakeOptimise", MakeOptimiser);
|
||||
@ -107,6 +112,7 @@ static void InitIniCommands(SicsInterp * pInter)
|
||||
PCMD("sicscron", MakeCron);
|
||||
PCMD("sicsdatafactory", SICSDataFactory);
|
||||
PCMD("sicsdescriptor", SICSDescriptor);
|
||||
PCMD("SICSLog", LogOutput);
|
||||
PCMD("sicsprompt", SicsPrompt);
|
||||
PCMD("SICSStatus", SICSStatus);
|
||||
PCMD("sicstime", SICSTime);
|
||||
@ -126,8 +132,6 @@ static void InitIniCommands(SicsInterp * pInter)
|
||||
SCMD("AntiCollisionInstall", AntiColliderFactory);
|
||||
SCMD("ChopperAdapter", CHAdapterFactory);
|
||||
SCMD("InstallSinfox", InstallSinfox);
|
||||
SCMD("MakeAsyncProtocol", AsyncProtocolFactory);
|
||||
SCMD("MakeAsyncQueue", AsyncQueueFactory);
|
||||
SCMD("MakeBatchManager", MakeExeManager);
|
||||
SCMD("MakeChopper", ChocoFactory);
|
||||
SCMD("MakeCone", MakeCone);
|
||||
@ -240,6 +244,7 @@ int InitObjectCommands(pServer pServ, char *file)
|
||||
if(killStartupCommands){
|
||||
RemoveStartupCommands();
|
||||
}
|
||||
isDuringInitialization = 0;
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
54
protocol.c
54
protocol.c
@ -32,6 +32,10 @@ typedef struct __Protocol {
|
||||
int isDefaultSet;
|
||||
char *pProList[PROLISTLEN]; /* list of valid protocols? */
|
||||
} Protocol;
|
||||
/*================================================================================================
|
||||
WARNING: These two char arrays may replicate things defined elsewhere. They may be out of
|
||||
sync with the rest of SIS. Keep in mind.....
|
||||
==================================================================================================*/
|
||||
|
||||
char *pEventType[] = {
|
||||
"VALUECHANGE", /* 0 */
|
||||
@ -145,12 +149,11 @@ void DeleteProtocol(void *self)
|
||||
if (pOld->version) {
|
||||
free(pOld->version);
|
||||
}
|
||||
if (pOld->pProList) {
|
||||
i = 0;
|
||||
while (NULL != pOld->pProList[i]) {
|
||||
free(pOld->pProList[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
free(pOld);
|
||||
}
|
||||
@ -171,7 +174,7 @@ static int ContextDo(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
|
||||
comCon = SCCopyConnection(pCon);
|
||||
if (comCon == NULL) {
|
||||
SCWrite(pCon, "EROOR: out of memory in contextdo", eError);
|
||||
SCWrite(pCon, "ERROR: out of memory in contextdo", eError);
|
||||
return 0;
|
||||
}
|
||||
status = Tcl_GetInt(pSics->pTcl, argv[1], &comCon->transID);
|
||||
@ -188,7 +191,13 @@ static int ContextDo(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
SCWrite(pCon, "ERROR: no more memory", eError);
|
||||
return 0;
|
||||
}
|
||||
if(comCon->transID > 100000) {
|
||||
SCPrintf(comCon,eLog,"COMSTART %d", comCon->transID);
|
||||
}
|
||||
status = InterpExecute(pSics, comCon, command);
|
||||
if(comCon->transID > 100000) {
|
||||
SCPrintf(comCon,eLog,"COMEND %d", comCon->transID);
|
||||
}
|
||||
if (command != buffer)
|
||||
free(command);
|
||||
SCDeleteConnection(comCon);
|
||||
@ -271,29 +280,29 @@ static int ProtocolSet(SConnection * pCon, Protocol * pPro, char *pProName)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 1: /* normal (connection start default) */
|
||||
case PROTNORM: /* normal (connection start default) */
|
||||
SCSetWriteFunc(pMaster, SCNormalWrite);
|
||||
SCSetWriteFunc(pCon, SCNormalWrite);
|
||||
break;
|
||||
|
||||
case 2: /* outcodes */
|
||||
case PROTCODE: /* outcodes */
|
||||
SCSetWriteFunc(pMaster, SCWriteWithOutcode);
|
||||
SCSetWriteFunc(pCon, SCWriteWithOutcode);
|
||||
break;
|
||||
|
||||
case 3: /* json */
|
||||
case PROTJSON: /* json */
|
||||
SCSetWriteFunc(pCon, SCWriteJSON_String);
|
||||
SCSetWriteFunc(pMaster, SCWriteJSON_String);
|
||||
break;
|
||||
case 4: /* ACT */
|
||||
case PROTACT: /* ACT */
|
||||
SCSetWriteFunc(pMaster, SCACTWrite);
|
||||
SCSetWriteFunc(pCon, SCACTWrite);
|
||||
break;
|
||||
case 5:
|
||||
case PROTALL:
|
||||
SCSetWriteFunc(pMaster, SCAllWrite);
|
||||
SCSetWriteFunc(pCon, SCAllWrite);
|
||||
break;
|
||||
case 0: /* default = psi_sics */
|
||||
case PROTSICS: /* default = psi_sics */
|
||||
default:
|
||||
SCSetWriteFunc(pMaster, pPro->defaultWriter);
|
||||
SCSetWriteFunc(pCon, pPro->defaultWriter);
|
||||
@ -332,11 +341,11 @@ int ProtocolGet(SConnection * pCon, void *pData, char *pProName, int len)
|
||||
|
||||
/* check list of protocols for valid name */
|
||||
switch (Index) {
|
||||
case 0: /* default = psi_sics */
|
||||
case 1: /* normal (connection start default) */
|
||||
case 2: /* outcodes */
|
||||
case 3: /* json */
|
||||
case 4: /* act */
|
||||
case PROTSICS: /* default = psi_sics */
|
||||
case PROTNORM: /* normal (connection start default) */
|
||||
case PROTCODE: /* outcodes */
|
||||
case PROTJSON: /* json */
|
||||
case PROTACT: /* act */
|
||||
pProName = pPro->pProList[Index];
|
||||
return 1;
|
||||
break;
|
||||
@ -441,7 +450,7 @@ static int InitDefaultProtocol(SConnection * pCon, Protocol * pPro)
|
||||
if (0 == pPro->isDefaultSet) {
|
||||
pPro->defaultWriter = SCGetWriteFunc(pCon);
|
||||
pPro->isDefaultSet = 1;
|
||||
pCon->iProtocolID = 0;
|
||||
pCon->iProtocolID = PROTSICS;
|
||||
}
|
||||
return pPro->isDefaultSet;
|
||||
}
|
||||
@ -628,10 +637,11 @@ char *GetProtocolName(SConnection * pCon)
|
||||
|
||||
/* check list of protocols for valid name */
|
||||
switch (pCon->iProtocolID) {
|
||||
case 0: /* default = psi_sics */
|
||||
case 1: /* normal (connection start default) */
|
||||
case 2: /* outcodes */
|
||||
case 3: /* json */
|
||||
case PROTSICS: /* default = psi_sics */
|
||||
case PROTNORM: /* normal (connection start default) */
|
||||
case PROTCODE: /* outcodes */
|
||||
case PROTJSON: /* json */
|
||||
case PROTACT: /* act */
|
||||
return strdup(pPro->pProList[pCon->iProtocolID]);
|
||||
break;
|
||||
default:
|
||||
@ -654,13 +664,13 @@ writeFunc GetProtocolWriteFunc(SConnection * pCon)
|
||||
{
|
||||
if (pCon != NULL) {
|
||||
switch (pCon->iProtocolID) {
|
||||
case 2: /* outcodes */
|
||||
case PROTCODE: /* outcodes */
|
||||
return SCWriteWithOutcode;
|
||||
break;
|
||||
case 3: /* json */
|
||||
case PROTJSON: /* json */
|
||||
return SCWriteJSON_String;
|
||||
break;
|
||||
case 4:
|
||||
case PROTACT:
|
||||
return SCACTWrite;
|
||||
break;
|
||||
default:
|
||||
|
@ -15,6 +15,14 @@ static char *pProTags[3] = {
|
||||
#define esStart -1
|
||||
#define esFinish -2
|
||||
|
||||
/*---------------------- protocol defines -------------------------------*/
|
||||
#define PROTSICS 0
|
||||
#define PROTNORM 1
|
||||
#define PROTCODE 2
|
||||
#define PROTJSON 3
|
||||
#define PROTACT 4
|
||||
#define PROTALL 5
|
||||
|
||||
/*--------------------- lifecycle -------------------------------------- */
|
||||
int InstallProtocol(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[]);
|
||||
|
32
remob.c
32
remob.c
@ -313,7 +313,8 @@ static int RemTransact(RemServer * remserver, int nChan,
|
||||
int try;
|
||||
int argMask;
|
||||
RemChannel *rc = &remserver->rc[nChan];
|
||||
|
||||
pDynString errorResult;
|
||||
|
||||
try = 3;
|
||||
if (rc->timeout) { /* eat old responses */
|
||||
while (RemRead(rc, 0) > 0) {
|
||||
@ -339,6 +340,20 @@ tryagain:
|
||||
if (iRet <= 0)
|
||||
goto close;
|
||||
while (!StartsWith(rc->line, "TRANSACTIONFINISHED")) {
|
||||
if (StartsWith(rc->line, "ERROR:")) {
|
||||
errorResult = CreateDynString(60, 64);
|
||||
do {
|
||||
RemHandle(remserver);
|
||||
DynStringConcat(errorResult, rc->line);
|
||||
DynStringConcat(errorResult, "\n");
|
||||
iRet = RemRead(rc, 2000);
|
||||
} while (!StartsWith(rc->line, "TRANSACTIONFINISHED"));
|
||||
if (pCon != NULL) {
|
||||
SCPrintf(pCon, eError, "ERROR: in %s:\n%s", remserver->name, GetCharArray(errorResult));
|
||||
}
|
||||
DeleteDynString(errorResult);
|
||||
return -2;
|
||||
}
|
||||
RemHandle(remserver);
|
||||
va_start(ap, cmd);
|
||||
arg = va_arg(ap, char *);
|
||||
@ -448,15 +463,17 @@ static float RemobGetValue(void *pData, SConnection * pCon)
|
||||
SCDeleteConnection(remserver->conn);
|
||||
}
|
||||
remserver->conn = SCCopyConnection(pCon);
|
||||
none = -1.25e6;
|
||||
none = -1.234e32;
|
||||
value = none;
|
||||
snprintf(buf, sizeof(buf), "<%s", remob->name);
|
||||
/* get value needs only spy priviledge */
|
||||
iRet =
|
||||
RemTransact(remserver, 0, pCon, remob->name, buf, &value, ">", NULL);
|
||||
/*
|
||||
if (iRet <= 0) {
|
||||
return 0.0;
|
||||
}
|
||||
*/
|
||||
if (value != none) {
|
||||
return value;
|
||||
}
|
||||
@ -654,7 +671,13 @@ int RemobAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
remserver->conn = SCCopyConnection(pCon);
|
||||
}
|
||||
if (argc == 1) {
|
||||
iRet = RemTransact(remserver, nChan, pCon, remob->name, ">", NULL);
|
||||
/* filter out time stamps !=== */
|
||||
iRet = RemTransact(remserver, nChan, pCon, remob->name, "!===", ">", NULL);
|
||||
if (iRet < 0) {
|
||||
iRet = 0;
|
||||
} else {
|
||||
iRet = 1;
|
||||
}
|
||||
} else if (strcasecmp(argv[1], "interest") == 0) {
|
||||
/* ignore interest commands, as they would not work properly */
|
||||
iRet = 1;
|
||||
@ -666,7 +689,8 @@ int RemobAction(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
|
||||
cmd = Arg2Tcl0(argc - 1, argv + 1, buf, sizeof buf, remob->name);
|
||||
if (cmd) {
|
||||
RemTransact(remserver, nChan, pCon, cmd, ">", NULL);
|
||||
/* filter out time stamps !=== */
|
||||
RemTransact(remserver, nChan, pCon, cmd, "!===", ">", NULL);
|
||||
if (cmd != buf)
|
||||
free(cmd);
|
||||
}
|
||||
|
497
remoteobject.c
497
remoteobject.c
@ -2,7 +2,7 @@
|
||||
* Remote objects in sicsobj. This means accessing remote objects in a different
|
||||
* SICS server from a master SICS server.
|
||||
*
|
||||
* Reading is implementd according to this scheme:
|
||||
* Reading is implemented according to this scheme:
|
||||
*
|
||||
* * When a read connection is made between a local node and a remote node in slave, then a
|
||||
* callback is installed on remote node in slave.
|
||||
@ -17,7 +17,7 @@
|
||||
*
|
||||
* COPRYRIGHT: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, February 2015
|
||||
* Mark Koennecke, February-May 2015
|
||||
**/
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
@ -31,22 +31,29 @@
|
||||
#include <lld_blob.h>
|
||||
#include <dynstring.h>
|
||||
#include <stptok.h>
|
||||
#include <json/json.h>
|
||||
|
||||
#define OOM -5001 /* out of memory */
|
||||
#define TO -5002 /* timeout */
|
||||
|
||||
#define READACT 7654
|
||||
#define POCHACT 8437
|
||||
|
||||
static char *login = {"RemoteMaster 3ed4c656a15f0aa45e02fd5ec429225bb93b762e7eb06cc81a0b4f6c35c76184\r\n"};
|
||||
extern char *trim(char *txt);
|
||||
|
||||
static int transactionID = 100000;
|
||||
/*---------------------- our very private data structure -------------------*/
|
||||
typedef struct {
|
||||
char *host;
|
||||
int port;
|
||||
int readHandle;
|
||||
int writeHandle;
|
||||
int writeInUse;
|
||||
int handle;
|
||||
int transactHandle;
|
||||
int readList;
|
||||
int writeList;
|
||||
unsigned int connected;
|
||||
time_t nextHeartbeat;
|
||||
struct json_tokener *jtok;
|
||||
} RemoteOBJ, *pRemoteOBJ;
|
||||
/*----------------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
@ -59,6 +66,12 @@ typedef struct {
|
||||
char *remotePath;
|
||||
} UpdateCallback, *pUpdateCallback;
|
||||
/*----------------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
int transID;
|
||||
SConnection *pCon;
|
||||
int waitTask;
|
||||
}writeData, *pWriteData;
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void KillRemoteOBJ(void *data)
|
||||
{
|
||||
char roTaskName[132];
|
||||
@ -68,66 +81,13 @@ void KillRemoteOBJ(void *data)
|
||||
snprintf(roTaskName,sizeof(roTaskName),"ro-%s-%d", self->host, self->port);
|
||||
StopTask(pServ->pTasker,roTaskName);
|
||||
free(self->host);
|
||||
ANETclose(self->readHandle);
|
||||
ANETclose(self->writeHandle);
|
||||
ANETclose(self->handle);
|
||||
ANETclose(self->transactHandle);
|
||||
LLDdeleteBlob(self->readList);
|
||||
LLDdeleteBlob(self->writeList);
|
||||
json_tokener_free(self->jtok);
|
||||
}
|
||||
}
|
||||
/*========================= reading related code ================================*/
|
||||
static int RemoteReadCallback(int handle, void *userData)
|
||||
{
|
||||
int length;
|
||||
char *pPtr, *pStart, *pEnd;
|
||||
|
||||
pPtr = ANETreadPtr(handle,&length);
|
||||
|
||||
/*
|
||||
* deal with command results
|
||||
*/
|
||||
pStart = strstr(pPtr, "TRANSACTIONSTART");
|
||||
pEnd = strstr(pPtr,"TRANSACTIONEND");
|
||||
if(pStart != NULL && pEnd != NULL){
|
||||
pStart = pStart + strlen("TRANSACTIONSTART");
|
||||
*pEnd = '\0';
|
||||
traceIO("RO","Received command - reply: %s", pStart);
|
||||
pEnd += strlen("TRANSACTIONEND");
|
||||
ANETreadConsume(handle,pEnd - pPtr);
|
||||
}
|
||||
|
||||
/*
|
||||
* deal with update messages
|
||||
*/
|
||||
pStart = strstr(pPtr, "SROC:");
|
||||
pEnd = strstr(pPtr,":EROC\r\n");
|
||||
if(pStart != NULL && pEnd != NULL){
|
||||
pStart += strlen("SROC:");
|
||||
*pEnd = '\0';
|
||||
InterpExecute(pServ->pSics, pServ->dummyCon,pStart);
|
||||
traceIO("RO", "Received %s from remote", pStart);
|
||||
pEnd += strlen("EROC\r\n");
|
||||
ANETreadConsume(handle,pEnd - pPtr);
|
||||
}
|
||||
|
||||
/*
|
||||
* deal with heartbeats
|
||||
*/
|
||||
if((pStart = strstr(pPtr,"Poch")) != NULL){
|
||||
ANETreadConsume(handle,(pStart+4) - pPtr);
|
||||
}
|
||||
|
||||
/*
|
||||
If there is more stuff to process: recurse
|
||||
*/
|
||||
pPtr = ANETreadPtr(handle,&length);
|
||||
if(length > 0 &&
|
||||
( strstr(pPtr,":EROC\r\n") != NULL ||
|
||||
strstr(pPtr,"TRANSACTIONEND") != NULL
|
||||
|| strstr(pPtr,"Poch") != NULL ) ) {
|
||||
RemoteReadCallback(handle,userData);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
static int transactCommand(int handle, char *command, char *reply, int replyLen)
|
||||
{
|
||||
@ -135,7 +95,7 @@ static int transactCommand(int handle, char *command, char *reply, int replyLen)
|
||||
char *prefix = {"transact "};
|
||||
int status, length, type;
|
||||
time_t start;
|
||||
char *pPtr;
|
||||
char *pPtr, *pEnd;
|
||||
|
||||
/*
|
||||
* read possible dirt of the line
|
||||
@ -144,12 +104,15 @@ static int transactCommand(int handle, char *command, char *reply, int replyLen)
|
||||
ANETreadConsume(handle,length);
|
||||
|
||||
|
||||
toSend = malloc(strlen(command) + strlen(prefix) + 1);
|
||||
toSend = malloc(strlen(command) + strlen(prefix) + 10);
|
||||
if(toSend == NULL){
|
||||
return OOM;
|
||||
}
|
||||
strcpy(toSend, prefix);
|
||||
strcat(toSend, command);
|
||||
if(strstr(command,"\n") == NULL){
|
||||
strcat(toSend,"\r\n");
|
||||
}
|
||||
status = ANETwrite(handle,toSend,strlen(toSend));
|
||||
free(toSend);
|
||||
if(status != 1){
|
||||
@ -163,7 +126,8 @@ static int transactCommand(int handle, char *command, char *reply, int replyLen)
|
||||
while(time(NULL) < start + 2.0){
|
||||
ANETprocess();
|
||||
pPtr = ANETreadPtr(handle,&length);
|
||||
if(length > 0 && strstr(pPtr,"TRANSACTIONFINISHED") != NULL){
|
||||
if(length > 0 && (pEnd = strstr(pPtr,"TRANSACTIONFINISHED")) != NULL){
|
||||
*pEnd = '\0';
|
||||
strncpy(reply,pPtr,replyLen);
|
||||
ANETreadConsume(handle,length);
|
||||
return 1;
|
||||
@ -191,9 +155,9 @@ static void ConnectRemoteObject(pRemoteOBJ self)
|
||||
return;
|
||||
}
|
||||
|
||||
self->readHandle = ANETconnect(self->host, self->port);
|
||||
self->writeHandle = ANETconnect(self->host, self->port);
|
||||
if(self->readHandle < 0 || self->writeHandle < 0){
|
||||
self->handle = ANETconnect(self->host, self->port);
|
||||
self->transactHandle = ANETconnect(self->host, self->port);
|
||||
if(self->handle < 0 || self->transactHandle < 0){
|
||||
self->connected = 0;
|
||||
traceIO("RO","Failed to connect to remote objects at %s, port %d",
|
||||
self->host, self->port);
|
||||
@ -206,23 +170,20 @@ static void ConnectRemoteObject(pRemoteOBJ self)
|
||||
Default login with hard coded manager login. Defined in
|
||||
nserver.c
|
||||
*/
|
||||
ANETwrite(self->readHandle,login,strlen(login));
|
||||
ANETwrite(self->writeHandle,login,strlen(login));
|
||||
ANETwrite(self->handle,login,strlen(login));
|
||||
ANETwrite(self->transactHandle,login,strlen(login));
|
||||
usleep(500);
|
||||
ANETprocess();
|
||||
/*
|
||||
eat the login responses
|
||||
*/
|
||||
pPtr = ANETreadPtr(self->readHandle, &length);
|
||||
ANETreadConsume(self->readHandle,length);
|
||||
pPtr = ANETreadPtr(self->writeHandle, &length);
|
||||
ANETreadConsume(self->writeHandle,length);
|
||||
pPtr = ANETreadPtr(self->handle, &length);
|
||||
ANETreadConsume(self->handle,length);
|
||||
pPtr = ANETreadPtr(self->transactHandle, &length);
|
||||
ANETreadConsume(self->transactHandle,length);
|
||||
|
||||
transactCommand(self->handle,"protocol set json\r\n", command,sizeof(command)-1);
|
||||
|
||||
/*
|
||||
* install the read callback
|
||||
*/
|
||||
ANETsetReadCallback(self->readHandle,RemoteReadCallback, NULL, NULL);
|
||||
|
||||
/*
|
||||
* Remove geterror on read nodes and reinstall callbacks for reconnects
|
||||
@ -233,17 +194,15 @@ static void ConnectRemoteObject(pRemoteOBJ self)
|
||||
node = FindHdbNode(NULL,rd.localNode,NULL);
|
||||
if(node != NULL){
|
||||
SetHdbProperty(node,"geterror",NULL);
|
||||
snprintf(command,sizeof(command),"fulltransact addremotecb %s %s \r\n",
|
||||
rd.remoteNode, rd.localNode);
|
||||
ANETwrite(self->readHandle,command,strlen(command));
|
||||
snprintf(command,sizeof(command),"contextdo %d addremotecb %s %s \r\n",
|
||||
READACT, rd.remoteNode, rd.localNode);
|
||||
ANETwrite(self->handle,command,strlen(command));
|
||||
}
|
||||
status = LLDnodePtr2Next(self->readList);
|
||||
}
|
||||
|
||||
transactCommand(self->writeHandle,"protocol set withcode\r\n", command,sizeof(command));
|
||||
|
||||
|
||||
self->connected = 1;
|
||||
self->writeInUse = 0;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
static void MarkDisconnected(pRemoteOBJ self)
|
||||
@ -270,8 +229,8 @@ static hdbCallbackReturn ROUpdateCallback(pHdb currentNode, void *userData,
|
||||
pUpdateCallback uppi = (pUpdateCallback)userData;
|
||||
hdbDataMessage *mm = NULL;
|
||||
pDynString text;
|
||||
char *prefix = {"SROC:hupdate "};
|
||||
char *postfix= {":EROC\r\n"};
|
||||
char *prefix = {"hupdate "};
|
||||
char *postfix= {" \r\n"};
|
||||
char *txt = NULL;
|
||||
int length;
|
||||
pHdbPropertyChange propChange = NULL;
|
||||
@ -309,7 +268,7 @@ static hdbCallbackReturn ROUpdateCallback(pHdb currentNode, void *userData,
|
||||
if(!SCisConnected(uppi->sendCon)){
|
||||
return hdbKill;
|
||||
}
|
||||
length = strlen("SROC:hdelprop ") + strlen(uppi->remotePath) +
|
||||
length = strlen("hdelprop ") + strlen(uppi->remotePath) +
|
||||
strlen(propChange->key) + 10;
|
||||
if(propChange->value != NULL){
|
||||
length += strlen(propChange->value);
|
||||
@ -319,10 +278,10 @@ static hdbCallbackReturn ROUpdateCallback(pHdb currentNode, void *userData,
|
||||
return hdbContinue;
|
||||
}
|
||||
if(propChange->value == NULL){
|
||||
snprintf(txt,length,"SROC:hdelprop %s %s %s", uppi->remotePath,
|
||||
snprintf(txt,length,"hdelprop %s %s %s", uppi->remotePath,
|
||||
propChange->key,postfix);
|
||||
} else {
|
||||
snprintf(txt,length,"SROC:hsetprop %s %s %s %s", uppi->remotePath,
|
||||
snprintf(txt,length,"hsetprop %s %s %s %s", uppi->remotePath,
|
||||
propChange->key,propChange->value, postfix);
|
||||
}
|
||||
SCWrite(uppi->sendCon,txt,eValue);
|
||||
@ -397,7 +356,7 @@ static int ConnectRead(pRemoteOBJ self, SConnection * pCon, ReadData rd)
|
||||
* Get information about the remote node and check compatability
|
||||
*/
|
||||
snprintf(command,sizeof(command),"hinfo %s\r\n", rd.remoteNode);
|
||||
status = transactCommand(self->writeHandle,command,reply,sizeof(reply));
|
||||
status = transactCommand(self->transactHandle,command,reply,sizeof(reply));
|
||||
if(status != 1){
|
||||
/*
|
||||
* try a reconnect,
|
||||
@ -407,7 +366,7 @@ static int ConnectRead(pRemoteOBJ self, SConnection * pCon, ReadData rd)
|
||||
*/
|
||||
self->connected = 0;
|
||||
ConnectRemoteObject(self);
|
||||
status = transactCommand(self->writeHandle,command,reply,sizeof(reply));
|
||||
status = transactCommand(self->transactHandle,command,reply,sizeof(reply));
|
||||
if(status != 1){
|
||||
SCPrintf(pCon,eWarning,"WARNING: cannot yet reach slave %s, but continuing...",
|
||||
self->host);
|
||||
@ -448,9 +407,9 @@ static int ConnectRead(pRemoteOBJ self, SConnection * pCon, ReadData rd)
|
||||
* Install a callback on the remote node to update the master. The remote should
|
||||
* then immediatly send an update which will be processed by the read callback.
|
||||
*/
|
||||
snprintf(command,sizeof(command),"fulltransact addremotecb %s %s \r\n",
|
||||
rd.remoteNode, rd.localNode);
|
||||
ANETwrite(self->readHandle,command,strlen(command));
|
||||
snprintf(command,sizeof(command),"contextdo %d addremotecb %s %s \r\n",
|
||||
READACT, rd.remoteNode, rd.localNode);
|
||||
ANETwrite(self->handle,command,strlen(command));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -492,10 +451,10 @@ static int HeartbeatTask(void *pData)
|
||||
{
|
||||
pRemoteOBJ self = (pRemoteOBJ)pData;
|
||||
int status;
|
||||
char command[] = {"Poch\r\n"};
|
||||
char command[] = {"contextdo 8437 Poch\r\n"};
|
||||
|
||||
if (time(NULL) > self->nextHeartbeat){
|
||||
status = ANETwrite(self->readHandle,command, strlen(command));
|
||||
status = ANETwrite(self->handle,command, strlen(command));
|
||||
if(status != 1){
|
||||
traceIO("RO","Trying a reconnect to %s, %d", self->host, self->port);
|
||||
self->connected = 0;
|
||||
@ -509,11 +468,13 @@ static int HeartbeatTask(void *pData)
|
||||
return 1;
|
||||
}
|
||||
/*============================= writing related code ===========================
|
||||
The logic here is to use the standard writeHandle when available. I expect most
|
||||
communication to be short and to happen through the writeHandle. If that one is
|
||||
in use, a new connection will be built.
|
||||
---------------------------------------------------------------------------------
|
||||
suppress all superfluous OK from the slave
|
||||
This works by sending the command via contextdo with a ID > 10^6. This causes
|
||||
the remote SICS to send the termination messages. The transaction IDs together
|
||||
with the connection responsible for it are kept in a list.
|
||||
|
||||
This list is used by the write task to forward messages properly and for handling
|
||||
termination.
|
||||
|
||||
-----------------------------------------------------------------------------------*/
|
||||
#include <outcode.c>
|
||||
static OutCode findOutCode(char *txt)
|
||||
@ -527,93 +488,153 @@ static OutCode findOutCode(char *txt)
|
||||
}
|
||||
return eValue;
|
||||
}
|
||||
/*--------------------------------------------------------------------------------*/
|
||||
static void printSICS(char *answer, SConnection *pCon)
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
static void CheckWriteList(int writeList,int transID, OutCode eOut, char *pText)
|
||||
{
|
||||
char line[1024], *pPtr, *pCode;
|
||||
OutCode eCode;
|
||||
int status;
|
||||
writeData WD;
|
||||
|
||||
pPtr = answer;
|
||||
while(pPtr != NULL){
|
||||
memset(line,0,sizeof(line));
|
||||
pPtr = stptok(pPtr,line,sizeof(line),"\n");
|
||||
if(strstr(line,"OK") == NULL){
|
||||
pCode = strstr(line,"@@");
|
||||
if(pCode != NULL){
|
||||
*pCode = '\0';
|
||||
pCode += 2;
|
||||
eCode = findOutCode(trim(pCode));
|
||||
|
||||
status = LLDnodePtr2First(writeList);
|
||||
while(status == 1){
|
||||
LLDblobData(writeList,&WD);
|
||||
if(WD.transID == transID){
|
||||
if(strstr(pText,"COMSTART") != NULL){
|
||||
/* skip */
|
||||
} else if(strstr(pText,"COMEND") != NULL && WD.waitTask == 0) {
|
||||
SCDeleteConnection(WD.pCon);
|
||||
LLDblobDelete(writeList);
|
||||
return;
|
||||
} else if(strstr(pText,"COMEND") != NULL && WD.waitTask == 1) {
|
||||
/* skip */
|
||||
return;
|
||||
} else if(strstr(pText,"TASKSTART") != NULL){
|
||||
WD.waitTask = 1 ;
|
||||
LLDblobDelete(writeList);
|
||||
LLDblobAppend(writeList,&WD, sizeof(writeData));
|
||||
return;
|
||||
} else if(strstr(pText,"TASKEND") != NULL && WD.waitTask == 1){
|
||||
SCDeleteConnection(WD.pCon);
|
||||
LLDblobDelete(writeList);
|
||||
return;
|
||||
} else {
|
||||
eCode = eValue;
|
||||
if(strstr(pText,"OK") == NULL){
|
||||
SCWrite(WD.pCon,pText,eOut);
|
||||
}
|
||||
return;
|
||||
}
|
||||
SCWrite(pCon,line,eCode);
|
||||
}
|
||||
status = LLDnodePtr2Next(writeList);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
static int PrepareWriteHandle(pRemoteOBJ self, SConnection *pCon, int *newHandle)
|
||||
}
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
static int WriteResponseTask(void *pData)
|
||||
{
|
||||
int handle, length;
|
||||
char *answer = NULL;
|
||||
char command[80];
|
||||
pRemoteOBJ self = (pRemoteOBJ)pData;
|
||||
int status, length = 0, transID;
|
||||
char *pText, *outTxt;
|
||||
json_object *message = NULL, *data = NULL;
|
||||
enum json_tokener_error tokerr;
|
||||
OutCode eOut;
|
||||
writeData WD;
|
||||
|
||||
if(self->writeInUse) {
|
||||
handle = ANETconnect(self->host,self->port);
|
||||
if(handle < 0){
|
||||
traceIO("RO","Failed to connect to %s at %d", self->host, self->port);
|
||||
if(pCon != NULL){
|
||||
SCPrintf(pCon,eError,"ERROR: Failed to connect to %s %d", self->host, self->port);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
ANETwrite(handle,login,strlen(login));
|
||||
usleep(500);
|
||||
ANETprocess();
|
||||
/*
|
||||
eat the login responses
|
||||
*/
|
||||
answer = ANETreadPtr(handle, &length);
|
||||
ANETreadConsume(handle,length);
|
||||
*newHandle = 1;
|
||||
|
||||
transactCommand(handle,"protocol set withcode\r\n", command,sizeof(command));
|
||||
|
||||
} else {
|
||||
self->writeInUse = 1;
|
||||
handle = self->writeHandle;
|
||||
/*
|
||||
eat dirt from the line
|
||||
*/
|
||||
answer = ANETreadPtr(handle, &length);
|
||||
ANETreadConsume(handle,length);
|
||||
if(!ANETvalidHandle(self->handle)) {
|
||||
return 1;
|
||||
}
|
||||
return handle;
|
||||
|
||||
pText = ANETreadPtr(self->handle,&length);
|
||||
while(length > 0){
|
||||
json_tokener_reset(self->jtok);
|
||||
message = json_tokener_parse_ex(self->jtok,pText,length);
|
||||
tokerr = self->jtok->err;
|
||||
if(tokerr == json_tokener_continue){
|
||||
return 1;
|
||||
} else if(tokerr != json_tokener_success) {
|
||||
traceIO("RO","JSON parsing error %s on %s from %s %d",
|
||||
json_tokener_errors[tokerr], pText, self->host, self->jtok->char_offset);
|
||||
ANETreadConsume(self->handle,length);
|
||||
return 1;
|
||||
}
|
||||
if(json_object_get_type(message) != json_type_object) {
|
||||
traceIO("RO","Received JSON of bad type in %s from %s",pText,self->host);
|
||||
ANETreadConsume(self->handle,length);
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
we need to consume here what has been parsed.
|
||||
The char_offset in the tokenizer structure might tell us that...
|
||||
*/
|
||||
ANETreadConsume(self->handle,self->jtok->char_offset);
|
||||
|
||||
|
||||
/*
|
||||
Received a valid message, process
|
||||
*/
|
||||
data = json_object_object_get(message,"trans");
|
||||
if(data == NULL){
|
||||
traceIO("RO","No transaction ID found in %s from %s", pText,self->host);
|
||||
return 1;
|
||||
}
|
||||
transID = json_object_get_int(data);
|
||||
|
||||
data = json_object_object_get(message,"flag");
|
||||
if(data == NULL){
|
||||
traceIO("RO","No flag found in %s from %s", pText,self->host);
|
||||
return 1;
|
||||
}
|
||||
outTxt = (char *)json_object_get_string(data);
|
||||
eOut = findOutCode(outTxt);
|
||||
|
||||
data = json_object_object_get(message,"data");
|
||||
if(data == NULL){
|
||||
traceIO("RO","No data found in %s from %s", pText,self->host);
|
||||
return 1;
|
||||
}
|
||||
pText = (char *)json_object_get_string(data);
|
||||
|
||||
traceIO("RO","Received:%s:%d:%d:%s",self->host,transID,eOut,pText);
|
||||
|
||||
/*
|
||||
do nothing on Poch
|
||||
*/
|
||||
if(transID == POCHACT){
|
||||
pText = ANETreadPtr(self->handle,&length);
|
||||
json_object_put(message);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
process update messages
|
||||
*/
|
||||
if(transID == READACT){
|
||||
if(strstr(pText,"hupdate") != NULL || strstr(pText,"prop") != NULL){
|
||||
InterpExecute(pServ->pSics,pServ->dummyCon,pText);
|
||||
}
|
||||
traceIO("RO","Received %s from remote",pText);
|
||||
pText = ANETreadPtr(self->handle,&length);
|
||||
json_object_put(message);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
check write List
|
||||
*/
|
||||
CheckWriteList(self->writeList,transID,eOut,pText);
|
||||
json_object_put(message);
|
||||
|
||||
pText = ANETreadPtr(self->handle,&length);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
static void ProcessWriteResponse(pRemoteOBJ self, int handle, SConnection *pCon)
|
||||
static int IncrementTransactionID()
|
||||
{
|
||||
char *answer = NULL, *pEnd, *command = NULL;
|
||||
int length;
|
||||
|
||||
while(1){
|
||||
TaskYield(pServ->pTasker);
|
||||
if(!ANETvalidHandle(handle)){
|
||||
SCPrintf(pCon,eError,"ERROR: Disconnected from %s", self->host);
|
||||
break;
|
||||
}
|
||||
answer = ANETreadPtr(handle,&length);
|
||||
if(length > 0 && (pEnd = strstr(answer,"TRANSACTIONFINISHED")) != NULL){
|
||||
if(pCon != NULL){
|
||||
*pEnd = '\0';
|
||||
printSICS(answer,pCon);
|
||||
}
|
||||
traceIO("RO","%s:%d: Received %s", self->host, self->port,answer);
|
||||
ANETreadConsume(handle,length);
|
||||
break;
|
||||
}
|
||||
transactionID++;
|
||||
if(transactionID >= 200000){
|
||||
transactionID = 100000;
|
||||
}
|
||||
|
||||
return transactionID;
|
||||
}
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
static hdbCallbackReturn ROWriteCallback(pHdb currentNode, void *userData,
|
||||
@ -626,14 +647,10 @@ static hdbCallbackReturn ROWriteCallback(pHdb currentNode, void *userData,
|
||||
pDynString data;
|
||||
char *remoteNode;
|
||||
char *command, *answer, *pEnd;
|
||||
|
||||
writeData WD;
|
||||
|
||||
if((mm = GetHdbSetMessage(mes)) != NULL){
|
||||
pCon = (SConnection *)mm->callData;
|
||||
handle = PrepareWriteHandle(self,pCon,&newHandle);
|
||||
if(handle < 0){
|
||||
return hdbAbort;
|
||||
}
|
||||
|
||||
/*
|
||||
build the command to send
|
||||
@ -648,53 +665,32 @@ static hdbCallbackReturn ROWriteCallback(pHdb currentNode, void *userData,
|
||||
}
|
||||
return hdbAbort;
|
||||
}
|
||||
snprintf(command,length,"transact hset %s %s\r\n",remoteNode, GetCharArray(data));
|
||||
WD.pCon = SCCopyConnection(pCon);
|
||||
WD.waitTask = 0;
|
||||
WD.transID = IncrementTransactionID();
|
||||
snprintf(command,length,"contextdo %d hset %s %s\r\n",
|
||||
WD.transID, remoteNode, GetCharArray(data));
|
||||
|
||||
/*
|
||||
write
|
||||
*/
|
||||
traceIO("RO","%s:%d: Sending %s ", self->host, self->port, command);
|
||||
status = ANETwrite(handle,command,strlen(command));
|
||||
LLDblobAppend(self->writeList,&WD,sizeof(writeData));
|
||||
status = ANETwrite(self->handle,command,strlen(command));
|
||||
free(command);
|
||||
DeleteDynString(data);
|
||||
if(status < 0){
|
||||
if(pCon != NULL){
|
||||
SCPrintf(pCon,eError,"ERROR: remote %s on %s disconnected", remoteNode, self->host);
|
||||
}
|
||||
return hdbAbort;
|
||||
}
|
||||
|
||||
/*
|
||||
wait for a response: TRANSACTIONFINISHED
|
||||
*/
|
||||
ProcessWriteResponse(self,handle,pCon);
|
||||
|
||||
/*
|
||||
Is there a termination script?
|
||||
*/
|
||||
command = GetHdbProp(currentNode,"termscript");
|
||||
if(command != NULL){
|
||||
while(1) {
|
||||
TaskYield(pServ->pTasker);
|
||||
Tcl_Eval(InterpGetTcl(pServ->pSics),command);
|
||||
answer = (char *)Tcl_GetStringResult(InterpGetTcl(pServ->pSics));
|
||||
if(strstr(answer,"idle") != NULL){
|
||||
answer = ANETreadPtr(handle,&length);
|
||||
printSICS(answer,pCon);
|
||||
traceIO("RO","%s:%d:Received %s", self->host,self->port,answer);
|
||||
ANETreadConsume(handle,length);
|
||||
break;
|
||||
}
|
||||
self->connected = 0;
|
||||
ConnectRemoteObject(self);
|
||||
if(self->connected == 0){
|
||||
if(pCon != NULL){
|
||||
SCPrintf(pCon,eError,"ERROR: remote %s on %s disconnected",
|
||||
remoteNode, self->host);
|
||||
}
|
||||
return hdbAbort;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(newHandle){
|
||||
ANETclose(handle);
|
||||
} else {
|
||||
self->writeInUse = 0;
|
||||
}
|
||||
|
||||
return hdbContinue;
|
||||
}
|
||||
|
||||
return hdbContinue;
|
||||
@ -722,12 +718,17 @@ static int ConnectWrite(pRemoteOBJ self, SConnection *pCon, ReadData rd)
|
||||
SetHdbProperty(localNode,"remotewrite",rd.remoteNode);
|
||||
AppendHipadabaCallback(localNode, MakeHipadabaCallback(ROWriteCallback,
|
||||
self,NULL));
|
||||
/*
|
||||
TODO: The connected write nodes should be held in a list in order to be able to
|
||||
remove the write callbacks when deleting the remote object. As removing remote
|
||||
objects usually only happens when SICS shuts down this is not so important.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get information about the remote node and check compatability
|
||||
*/
|
||||
snprintf(command,sizeof(command),"hinfo %s\r\n", rd.remoteNode);
|
||||
status = transactCommand(self->writeHandle,command,reply,sizeof(reply));
|
||||
status = transactCommand(self->transactHandle,command,reply,sizeof(reply));
|
||||
if(status != 1){
|
||||
SCPrintf(pCon,eWarning,"WARNING: cannot yet reach slave %s, but continuing...",
|
||||
self->host);
|
||||
@ -784,61 +785,21 @@ static int ConnectwriteCmd(pSICSOBJ ccmd, SConnection * pCon,
|
||||
/*============================ remote execute =================================*/
|
||||
static int RemoteExecute(pRemoteOBJ self, SConnection *pCon, char *command)
|
||||
{
|
||||
int status, handle, newHandle = 0, length;
|
||||
char *answer, *pEnd;
|
||||
|
||||
handle = PrepareWriteHandle(self,pCon,&newHandle);
|
||||
if(handle < 0){
|
||||
return 0;
|
||||
}
|
||||
int status;
|
||||
char answer[65536];
|
||||
|
||||
/*
|
||||
write, thereby taking care to prefix with transact and for proper termination
|
||||
*/
|
||||
if(strstr(command,"transact") == NULL){
|
||||
ANETwrite(handle,"transact ", sizeof("transact "));
|
||||
}
|
||||
status = ANETwrite(handle,command,strlen(command));
|
||||
if(strstr(command,"\n") == NULL){
|
||||
ANETwrite(handle,"\r\n",2);
|
||||
}
|
||||
if(status < 0){
|
||||
traceIO("RO","Disconnect from %s while executing %s", self->host, command);
|
||||
if(pCon != NULL){
|
||||
SCPrintf(pCon,eError,"ERROR: Disconnected from %s %d", self->host, self->port);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
wait for response
|
||||
*/
|
||||
while(1){
|
||||
TaskYield(pServ->pTasker);
|
||||
if(!ANETvalidHandle(handle)){
|
||||
if(pCon != NULL){
|
||||
SCPrintf(pCon,eError,"ERROR: Disconnected from %s %d", self->host, self->port);
|
||||
}
|
||||
break;
|
||||
}
|
||||
answer = ANETreadPtr(handle,&length);
|
||||
if(length > 0 && (pEnd = strstr(answer,"TRANSACTIONFINISHED")) != NULL){
|
||||
if(pCon != NULL){
|
||||
*pEnd = '\0';
|
||||
SCPrintf(pCon,eValue,answer);
|
||||
}
|
||||
ANETreadConsume(handle,length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(newHandle){
|
||||
ANETclose(handle);
|
||||
memset(answer,0,sizeof(answer)-1);
|
||||
status = transactCommand(self->transactHandle,command,answer,sizeof(answer));
|
||||
if(status == 1){
|
||||
SCWrite(pCon,answer,eValue);
|
||||
} else {
|
||||
self->writeInUse = 0;
|
||||
SCPrintf(pCon,eError,"ERROR: Disconnected from %s %d", self->host, self->port);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return status;
|
||||
}
|
||||
/*------------------------------------------------------------------------------*/
|
||||
static int RemoteExecuteCmd(pSICSOBJ ccmd, SConnection * pCon,
|
||||
@ -920,6 +881,8 @@ static int MakeRemoteObject(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
self->host = strdup(argv[2]);
|
||||
self->port = atoi(argv[3]);
|
||||
self->readList = LLDblobCreate();
|
||||
self->writeList = LLDblobCreate();
|
||||
self->jtok = json_tokener_new();
|
||||
ConnectRemoteObject(self);
|
||||
|
||||
cmd = AddSICSHdbPar(pNew->objectNode,
|
||||
@ -949,6 +912,8 @@ static int MakeRemoteObject(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
|
||||
snprintf(roTaskName,sizeof(roTaskName),"ro-%s-%d", self->host, self->port);
|
||||
TaskRegisterN(pServ->pTasker, roTaskName, HeartbeatTask, NULL,NULL,self,1);
|
||||
snprintf(roTaskName,sizeof(roTaskName),"rocom-%s-%d", self->host, self->port);
|
||||
TaskRegisterN(pServ->pTasker, roTaskName, WriteResponseTask, NULL,NULL,self,1);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
2
sansbc.c
2
sansbc.c
@ -201,7 +201,7 @@ static int StatCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
|
||||
}
|
||||
average = (double)sum/(double)length;
|
||||
|
||||
SCPrintf(pCon,eValue,"Stat:sum,max,min,av = %d,%d,%d,%f", sum,max,min,average);
|
||||
SCPrintf(pCon,eValue,"Stat:sum,max,min,av = %ld,%ld,%ld,%f", sum,max,min,average);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
4
scan.c
4
scan.c
@ -152,6 +152,8 @@ pScanData CreateScanObject(char *pRecover, char *pHeader, pCounter pCount,
|
||||
/* assign various things */
|
||||
if (pRecover) {
|
||||
strlcpy(pNew->pRecover, pRecover,1024);
|
||||
} else {
|
||||
memset(pNew->pRecover,0,sizeof(pNew->pRecover));
|
||||
}
|
||||
if (pHeader) {
|
||||
strlcpy(pNew->pHeaderFile, pHeader,1024);
|
||||
@ -597,7 +599,7 @@ static int ScanLoop(pScanData self)
|
||||
InvokeCallBack(self->pCall, SCANPOINT, self);
|
||||
|
||||
self->WriteScanPoints(self, i);
|
||||
if (self->pRecover) {
|
||||
if (strlen(self->pRecover) > 10) {
|
||||
WriteRecover(self);
|
||||
}
|
||||
}
|
||||
|
@ -404,6 +404,7 @@ static char *SctActionHandler(void *actionData, char *lastReply,
|
||||
char *errorScript = NULL;
|
||||
char *send = NULL;
|
||||
int i;
|
||||
int j;
|
||||
SConnection *con;
|
||||
char eprop[80];
|
||||
char msg[1024];
|
||||
@ -431,23 +432,24 @@ static char *SctActionHandler(void *actionData, char *lastReply,
|
||||
* property result to the data from the device. Read this now and
|
||||
* print it if diagnostics is required.
|
||||
*/
|
||||
SetProp(node, controller->node, "result", lastReply);
|
||||
script = NULL;
|
||||
if (!commError && controller->verbose && lastReply != NULL
|
||||
&& *lastReply != '\0') {
|
||||
SCPrintf(con, eLog, "%6.3f reply : %s\n", secondsOfMinute(), lastReply);
|
||||
if (lastReply != NULL) {
|
||||
SetProp(node, controller->node, "result", lastReply);
|
||||
if (*lastReply != '\0') {
|
||||
if (!commError && controller->verbose) {
|
||||
SCPrintf(con, eLog, "%6.3f reply : %s\n", secondsOfMinute(), lastReply);
|
||||
}
|
||||
if(!commError && controller->fd != NULL) {
|
||||
fprintf(controller->fd, "%6.3f reply : %s\n", secondsOfMinute(), lastReply);
|
||||
}
|
||||
if(data != NULL && data->controller != NULL) {
|
||||
traceIO(data->controller->node->name, "reply:%s", lastReply);
|
||||
} else {
|
||||
traceIO("sctunknown", "reply:%s", lastReply);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!commError && controller->fd != NULL && lastReply != NULL && *lastReply != '\0'){
|
||||
fprintf(controller->fd, "%6.3f reply : %s\n", secondsOfMinute(), lastReply);
|
||||
}
|
||||
if(lastReply != NULL && *lastReply != '\0'){
|
||||
if(data != NULL && data->controller != NULL){
|
||||
traceIO(data->controller->node->name, "reply:%s", lastReply);
|
||||
} else {
|
||||
traceIO("sctunknown", "reply:%s", lastReply);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Make sure that the state property is set to the name of the property
|
||||
* which holds the name of the script to run at this stage.
|
||||
@ -521,7 +523,7 @@ static char *SctActionHandler(void *actionData, char *lastReply,
|
||||
traceIO(data->controller->node->name, "ERROR: action {%s} in {%s} node %s:\nERROR: %s",
|
||||
data->name, origScript, path, result);
|
||||
} else {
|
||||
traceIO("sctunknown", "reply:%s", "ERROR: action {%s} in {%s} node %s:\nERROR: %s",
|
||||
traceIO("sctunknown", "ERROR: action {%s} in {%s} node %s:\nERROR: %s",
|
||||
data->name, origScript, path, result);
|
||||
}
|
||||
}
|
||||
@ -529,6 +531,21 @@ static char *SctActionHandler(void *actionData, char *lastReply,
|
||||
if (strcasecmp(data->name, "read") == 0) {
|
||||
SetHdbProperty(node, "geterror", result);
|
||||
}
|
||||
/* Sanitize the text to reduce TCL problems with unbalanced and substituted items */
|
||||
for (j = 0; msg[j]; ++j) {
|
||||
switch (msg[j]) {
|
||||
case '{':
|
||||
case '}':
|
||||
case '[':
|
||||
case ']':
|
||||
case '<':
|
||||
case '>':
|
||||
case '\'':
|
||||
case '"':
|
||||
case '$':
|
||||
msg[j] = '_';
|
||||
}
|
||||
}
|
||||
SetHdbProperty(node, eprop, msg);
|
||||
blank = strchr(origScript, ' ');
|
||||
if (blank != NULL) {
|
||||
@ -544,6 +561,21 @@ static char *SctActionHandler(void *actionData, char *lastReply,
|
||||
}
|
||||
cnt++;
|
||||
snprintf(msg, sizeof msg, "%dx {%s}: %s", cnt, origScript, result);
|
||||
/* Sanitize the text to reduce TCL problems with unbalanced and substituted items */
|
||||
for (j = 0; msg[j]; ++j) {
|
||||
switch (msg[j]) {
|
||||
case '{':
|
||||
case '}':
|
||||
case '[':
|
||||
case ']':
|
||||
case '<':
|
||||
case '>':
|
||||
case '\'':
|
||||
case '"':
|
||||
case '$':
|
||||
msg[j] = '_';
|
||||
}
|
||||
}
|
||||
SetHdbProperty(node, eprop, msg);
|
||||
send = NULL;
|
||||
free(script);
|
||||
@ -951,12 +983,15 @@ int SctAddPollNode(SctController * controller, Hdb * node, double interval,
|
||||
{
|
||||
SctData *data;
|
||||
hdbCallback *cb;
|
||||
|
||||
char nodePath[512], info[1024];
|
||||
|
||||
if (!FindHdbCallbackData(node, controller)) {
|
||||
cb = MakeHipadabaCallback(SctMainCallback, controller, NULL);
|
||||
assert(cb);
|
||||
AppendHipadabaCallback(node, cb);
|
||||
SetHdbProperty(node, "geterror", "Not read yet");
|
||||
GetHdbPath(node, nodePath, sizeof nodePath);
|
||||
snprintf(info, 1023, "%s: Not read yet", nodePath);
|
||||
SetHdbProperty(node, "geterror", info);
|
||||
}
|
||||
|
||||
data = calloc(1, sizeof(*data));
|
||||
@ -1585,8 +1620,19 @@ static int SctProcessCmd(pSICSOBJ ccmd, SConnection * con,
|
||||
startTime = time(NULL);
|
||||
DevQueue(c->devser, data, WritePRIO,
|
||||
SctWriteHandler, SctTransactMatch, NULL, SctDataInfo);
|
||||
while (data->busy == 1 && time(NULL) < startTime + 20) {
|
||||
|
||||
while (data->busy == 1){
|
||||
TaskYield(pServ->pTasker);
|
||||
if(time(NULL) >= startTime + 20) {
|
||||
/*
|
||||
if data would still come after such a long timeout, it
|
||||
might end up in the next action: see comment in devser.c
|
||||
*/
|
||||
SCPrintf(con,eError,"ERROR: timeout processing node %s", par[0]->value.v.text);
|
||||
DevRemoveAction(c->devser,data);
|
||||
SctKillData(data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
SctKillData(data);
|
||||
|
||||
|
@ -203,7 +203,7 @@ static int StartComTaskCmd(pSICSOBJ ccmd, SConnection * con,
|
||||
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||
{
|
||||
char *priority, *sendData;
|
||||
int lID;
|
||||
long lID;
|
||||
ComTaskManager *manni = NULL;
|
||||
|
||||
if(nPar < 2) {
|
||||
@ -294,7 +294,7 @@ const char *GetComTaskReply(ComTaskManager *manager,
|
||||
static int GetComTaskReplyCmd(pSICSOBJ ccmd, SConnection * con,
|
||||
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||
{
|
||||
int lID;
|
||||
long lID;
|
||||
int length;
|
||||
ComTaskManager *manni = NULL;
|
||||
const char *reply;
|
||||
@ -311,7 +311,7 @@ static int GetComTaskReplyCmd(pSICSOBJ ccmd, SConnection * con,
|
||||
SCPrintf(con,eError,"No reply for %ld found", lID);
|
||||
return 0;
|
||||
} else {
|
||||
SCPrintf(con,eValue,"%d = %s", lID, reply);
|
||||
SCPrintf(con,eValue,"%ld = %s", lID, reply);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
517
servlog.c
517
servlog.c
@ -47,16 +47,18 @@
|
||||
- NETWrites log message (if enabled) before attempt to write to file
|
||||
- uses OpenVerifyLogFile helper function (removed duplicate code)
|
||||
-----------------------------------------------------------------------------*/
|
||||
#include <stdarg.h>
|
||||
#include "fortify.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <strlutil.h>
|
||||
|
||||
#include "ifile.h"
|
||||
#include "conman.h"
|
||||
#include "servlog.h"
|
||||
#include "network.h"
|
||||
|
||||
@ -69,24 +71,142 @@
|
||||
this the following code is necessary.
|
||||
*/
|
||||
typedef struct __LogLog {
|
||||
SConnection *pCon;
|
||||
OutCode iOut;
|
||||
int iAllFlag;
|
||||
pSICSLogHook pFunc;
|
||||
void *pData;
|
||||
unsigned int code_bits;
|
||||
struct __LogLog *pNext;
|
||||
struct __LogLog *pPrevious;
|
||||
} CaptureEntry, *pCaptureEntry;
|
||||
|
||||
static pCaptureEntry pCapture = NULL;
|
||||
/*------------------------------------------------------------------------*/
|
||||
#include "outcode.c" /* for pCode */
|
||||
|
||||
int KillCapture(SConnection * pCon)
|
||||
const char* OutCodeToTxt(OutCode eOut)
|
||||
{
|
||||
switch (eOut) {
|
||||
case eInternal: return "Int"; /* internal */
|
||||
case eCommand: return "Cmd"; /* reserved, not used */
|
||||
case eHWError: return "ErH"; /* reserved, used only for SICSLog */
|
||||
case eInError: return "ErI"; /* reserved, used as a mark in the handling of output codes */
|
||||
case eStatus: return "Sta"; /* reserved, deprecated */
|
||||
case eValue: return "Val"; /* value reponse: copied into Tcl */
|
||||
case eStart: return "Beg"; /* start message */
|
||||
case eFinish: return "End"; /* finish message */
|
||||
case eEvent: return "Evt"; /* some callback messages */
|
||||
case eWarning: return "Wrn"; /* warnings */
|
||||
case eError: return "Err"; /* error: copied into Tcl */
|
||||
case eHdbValue: return "HVa"; /* hipadaba value chnage */
|
||||
case eHdbEvent: return "HEv"; /* Hipadaba event */
|
||||
case eLog: return "Log"; /* log message: is always written to client */
|
||||
case eLogError: return "ErL"; /* error message to log: is always written to client */
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
|
||||
const char* OutCodeToText(OutCode eOut)
|
||||
{
|
||||
switch (eOut) {
|
||||
case eInternal: return "Internal";
|
||||
case eCommand: return "Command";
|
||||
case eHWError: return "HWError";
|
||||
case eInError: return "InError";
|
||||
case eStatus: return "Status";
|
||||
case eValue: return "Value";
|
||||
case eStart: return "Start";
|
||||
case eFinish: return "Finish";
|
||||
case eEvent: return "Event";
|
||||
case eWarning: return "Warning";
|
||||
case eError: return "Error";
|
||||
case eHdbValue: return "HdbValue";
|
||||
case eHdbEvent: return "HdbEvent";
|
||||
case eLog: return "Log";
|
||||
case eLogError: return "LogError";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
int OutCodeFromText(const char *text, OutCode *outcode)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < iNoCodes; ++i) {
|
||||
if (strcasecmp(text, pCode[i]) == 0) {
|
||||
if (outcode)
|
||||
*outcode = i;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static unsigned int find_code_bits(const char *p1, const char *p2) {
|
||||
/* may be outcode, try find it */
|
||||
int i;
|
||||
const char *pShort;
|
||||
const char *pLong;
|
||||
size_t len = p2 - p1;
|
||||
if (len == 3 && strncasecmp(p1, "all", 3) == 0)
|
||||
return (1 << iNoCodes) - 1;
|
||||
for (i = 0; i < iNoCodes; ++i) {
|
||||
pShort = OutCodeToTxt(i);
|
||||
if (pShort && strncasecmp(p1, pShort, len) == 0)
|
||||
return 1 << i;
|
||||
pLong = OutCodeToText(i);
|
||||
if (pLong && strlen(pLong) == len) {
|
||||
if (strncasecmp(p1, pLong, len) == 0) {
|
||||
return 1 << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *AddSICSLogHook(pSICSLogHook func, const char *pCodes, void *pData)
|
||||
{
|
||||
unsigned int code_bits = 0;
|
||||
if (strcasecmp("all", pCodes) == 0)
|
||||
code_bits = (1 << iNoCodes) - 1;
|
||||
else {
|
||||
const char *p1, *p2;
|
||||
p1 = pCodes;
|
||||
while (NULL != (p2 = strchr(p1, ','))) {
|
||||
/* TODO [p1:p2) */
|
||||
code_bits |= find_code_bits(p1, p2);
|
||||
p1 = p2 + 1;
|
||||
}
|
||||
/* p1 points at the last or only code */
|
||||
/* TODO p1 */
|
||||
code_bits |= find_code_bits(p1, p1 + strlen(p1));
|
||||
}
|
||||
if (code_bits != 0) {
|
||||
pCaptureEntry pNew;
|
||||
pNew = (pCaptureEntry) malloc(sizeof(CaptureEntry));
|
||||
if (!pNew) {
|
||||
SICSLogWrite("Out of memory in LogCapture", eInternal);
|
||||
return NULL;
|
||||
}
|
||||
if (pCapture) {
|
||||
pCapture->pPrevious = pNew;
|
||||
}
|
||||
pNew->pPrevious = NULL;
|
||||
pNew->pNext = pCapture;
|
||||
pCapture = pNew;
|
||||
pNew->code_bits = code_bits;
|
||||
pNew->pFunc = func;
|
||||
pNew->pData = pData;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Remove any and all hooks with this pData */
|
||||
char *RemSICSLogHook(void *pData)
|
||||
{
|
||||
pCaptureEntry pCurrent, pTemp;
|
||||
|
||||
/* find first */
|
||||
pCurrent = pCapture;
|
||||
while (pCurrent != NULL) {
|
||||
if (pCon == pCurrent->pCon) {
|
||||
if (pData == pCurrent->pData) {
|
||||
/* relink */
|
||||
if (pCurrent->pPrevious) {
|
||||
pCurrent->pPrevious->pNext = pCurrent->pNext;
|
||||
@ -104,88 +224,27 @@ int KillCapture(SConnection * pCon)
|
||||
pCurrent = pCurrent->pNext;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
the command function:
|
||||
Syntax:
|
||||
Kill kills all logging
|
||||
Log OutCode starts loggin OutCode events
|
||||
All starts logging all events
|
||||
-------------------------------------------------------------------------- */
|
||||
#include "outcode.c" /* for pCode */
|
||||
|
||||
int LogCapture(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
/* Return bitmask of any and all hooks with this pData */
|
||||
unsigned int GetSICSLogHook(void *pData)
|
||||
{
|
||||
pCaptureEntry pNew = NULL;
|
||||
char pBueffel[512];
|
||||
int i;
|
||||
pCaptureEntry pCurrent, pTemp;
|
||||
unsigned int code_bits = 0;
|
||||
|
||||
/* check no af args */
|
||||
if (argc < 2) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "Insufficient number of argumenst to %s", argv[0]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
/* find first */
|
||||
pCurrent = pCapture;
|
||||
while (pCurrent != NULL) {
|
||||
if (pData == pCurrent->pData) {
|
||||
code_bits |= pCurrent->code_bits;
|
||||
}
|
||||
pCurrent = pCurrent->pNext;
|
||||
}
|
||||
argtolower(argc, argv);
|
||||
|
||||
/* Branch according to argv[1] */
|
||||
if (strcmp(argv[1], "kill") == 0) {
|
||||
KillCapture(pCon);
|
||||
return 1;
|
||||
} else if (strcmp(argv[1], "all") == 0) {
|
||||
pNew = (pCaptureEntry) malloc(sizeof(CaptureEntry));
|
||||
if (!pNew) {
|
||||
SICSLogWrite("Out of memory in LogCapture", eInternal);
|
||||
return 0;
|
||||
}
|
||||
if (pCapture) {
|
||||
pCapture->pPrevious = pNew;
|
||||
}
|
||||
pNew->pPrevious = NULL;
|
||||
pNew->pNext = pCapture;
|
||||
pCapture = pNew;
|
||||
pNew->iAllFlag = 1;
|
||||
pNew->pCon = pCon;
|
||||
return 1;
|
||||
} else {
|
||||
/* must be outcode, try find it */
|
||||
i = 0;
|
||||
while (pCode[i] != NULL) {
|
||||
if (strcmp(argv[1], pCode[i]) == 0) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (i > iNoCodes) {
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "OutPutCode %s not recognized in %s", argv[1],
|
||||
argv[0]);
|
||||
SCWrite(pCon, pBueffel, eError);
|
||||
return 0;
|
||||
}
|
||||
/* create a new one */
|
||||
pNew = (pCaptureEntry) malloc(sizeof(CaptureEntry));
|
||||
if (!pNew) {
|
||||
SICSLogWrite("Out of memory in LogCapture", eInternal);
|
||||
return 0;
|
||||
}
|
||||
if (pCapture) {
|
||||
pCapture->pPrevious = pNew;
|
||||
}
|
||||
pNew->pPrevious = NULL;
|
||||
pNew->pNext = pCapture;
|
||||
pCapture = pNew;
|
||||
pNew->iAllFlag = 0;
|
||||
pNew->pCon = pCon;
|
||||
pNew->iOut = i;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return code_bits;
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int HasLineFeed(char *pText)
|
||||
{
|
||||
@ -203,28 +262,67 @@ static int HasLineFeed(char *pText)
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define MAXLOG 10000
|
||||
#define MAXFILES 20
|
||||
static const char* timestamp(struct timeval *tp, char delim) {
|
||||
static char ts[80];
|
||||
int year, month, day;
|
||||
int hour, min, sec, usec;
|
||||
struct timeval tv;
|
||||
struct tm *time;
|
||||
if (tp)
|
||||
tv = *tp;
|
||||
else
|
||||
gettimeofday(&tv, NULL);
|
||||
time = localtime(&tv.tv_sec);
|
||||
year = 1900 + time->tm_year;
|
||||
month = time->tm_mon + 1;
|
||||
day = time->tm_mday;
|
||||
hour = time->tm_hour;
|
||||
min = time->tm_min;
|
||||
sec = time->tm_sec;
|
||||
usec = (int) tv.tv_usec;
|
||||
snprintf(ts, 80, "%04d-%02d-%02dT%02d%c%02d%c%02d.%06d",
|
||||
year, month, day, hour, delim, min, delim, sec, usec);
|
||||
return ts;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define MAXLOG 100000
|
||||
#define MAXFILES 100
|
||||
|
||||
static FILE *fLogFile = NULL;
|
||||
static int iFile = 0;
|
||||
static int iLineCount = 0;
|
||||
static int iLogUsable = 1;
|
||||
static char filnam[1024];
|
||||
static char prevfilnam[1024];
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int OpenVerifyLogFile()
|
||||
{
|
||||
char pFile[256];
|
||||
char filnam[512];
|
||||
char *pChar = NULL;
|
||||
char fPath[1024];
|
||||
|
||||
pChar = getenv("SICS_INIT_LOGPATH");
|
||||
if (!pChar) {
|
||||
snprintf(fPath, sizeof(fPath) - 1, "%s/", "../log");
|
||||
} else {
|
||||
snprintf(fPath, sizeof(fPath) - 1, "%s/", pChar);
|
||||
}
|
||||
|
||||
pChar = IFindOption(pSICSOptions, "LogFileBaseName");
|
||||
if (!pChar) { /* Try to write to file "server" in */
|
||||
strcpy(pFile, "server");
|
||||
} else {
|
||||
strlcpy(pFile, pChar, 255);
|
||||
strlcpy(pFile, pChar, sizeof(pFile) - 1);
|
||||
}
|
||||
snprintf(filnam, 511, "%s%2.2d.log", pFile, iFile);
|
||||
|
||||
snprintf(filnam, sizeof(filnam) - 1, "%s%s_%19.19s.%02d.log", fPath, pFile, timestamp(NULL, '-'), iFile);
|
||||
iFile++;
|
||||
if (iFile >= MAXFILES) {
|
||||
iFile = 0;
|
||||
}
|
||||
|
||||
fLogFile = fopen(filnam, "w");
|
||||
if (!fLogFile) {
|
||||
fprintf(stderr, "ERROR: Cannot open logfile %s for writing\n", pFile);
|
||||
@ -242,23 +340,21 @@ void SICSLogEnable(int flag)
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void SICSLogWrite(char *pText, OutCode eOut)
|
||||
static void SICSLogWriteFile(char *pText, OutCode eOut, struct timeval *tp)
|
||||
{
|
||||
char pFile[256];
|
||||
char *pChar = NULL;
|
||||
pCaptureEntry pCurrent;
|
||||
char pBueffel[256];
|
||||
int text_len;
|
||||
|
||||
#ifdef NOLOG
|
||||
return;
|
||||
#endif
|
||||
|
||||
text_len = strlen(pText);
|
||||
/* do all captured */
|
||||
pCurrent = pCapture;
|
||||
while (pCurrent) {
|
||||
if ((pCurrent->iOut == eOut) || (pCurrent->iAllFlag == 1)) {
|
||||
ANETwrite(pCurrent->pCon->sockHandle, pText, strlen(pText));
|
||||
ANETwrite(pCurrent->pCon->sockHandle, "\n", 1);
|
||||
if ((pCurrent->code_bits & (1 << eOut))) {
|
||||
pCurrent->pFunc(pText, eOut, pCurrent->pData);
|
||||
}
|
||||
pCurrent = pCurrent->pNext;
|
||||
}
|
||||
@ -273,23 +369,242 @@ void SICSLogWrite(char *pText, OutCode eOut)
|
||||
return;
|
||||
}
|
||||
iLogUsable = OpenVerifyLogFile();
|
||||
iLineCount = 0;
|
||||
}
|
||||
|
||||
/* switch file if too many lines */
|
||||
if (iLineCount >= MAXLOG) {
|
||||
fclose(fLogFile);
|
||||
fLogFile = NULL;
|
||||
iFile++;
|
||||
iLineCount = 0;
|
||||
if (iFile >= MAXFILES) {
|
||||
iFile = 0;
|
||||
}
|
||||
strcpy(prevfilnam, filnam);
|
||||
FILE *prevlog = fLogFile;
|
||||
|
||||
iLogUsable = OpenVerifyLogFile();
|
||||
iLineCount = 0;
|
||||
fprintf(prevlog, "%s: <<<close logfile>>> to %s\n",
|
||||
timestamp(NULL, ':'),
|
||||
filnam);
|
||||
fclose(prevlog);
|
||||
if (1 == iLogUsable) {
|
||||
fprintf(fLogFile, "%s: <<<open logfile>>> from %s\n",
|
||||
timestamp(NULL, ':'),
|
||||
prevfilnam);
|
||||
iLineCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (1 == iLogUsable) {
|
||||
fprintf(fLogFile, "%s\n", pText);
|
||||
if (iLineCount == 0)
|
||||
fprintf(fLogFile, "%s: <<<open logfile>>>\n", timestamp(NULL, ':'));
|
||||
fprintf(fLogFile, "%s:%s:", timestamp(tp, ':'), OutCodeToTxt(eOut));
|
||||
fprintf(fLogFile, "%s", pText);
|
||||
if (text_len < 1 || pText[text_len - 1] != '\n')
|
||||
fprintf(fLogFile, "\n");
|
||||
fflush(fLogFile);
|
||||
iLineCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void SICSLogWriteTimeCode(char *pText, OutCode eOut, struct timeval *tp, char code)
|
||||
{
|
||||
char buf[200];
|
||||
const char *cp;
|
||||
int idx = 0;
|
||||
struct timeval tv;
|
||||
|
||||
if (tp == NULL) {
|
||||
gettimeofday(&tv, NULL);
|
||||
tp = &tv;
|
||||
}
|
||||
if (isalnum(code)) {
|
||||
buf[idx++] = code;
|
||||
buf[idx++] = ':';
|
||||
}
|
||||
cp = pText;
|
||||
while (*cp) {
|
||||
if (*cp == '\n') {
|
||||
buf[idx++] = '\n';
|
||||
buf[idx++] = '\0';
|
||||
SICSLogWriteFile(buf, eOut, tp);
|
||||
idx = 0;
|
||||
buf[idx++] = '*';
|
||||
buf[idx++] = ':';
|
||||
} else if (*cp == '\r') {
|
||||
buf[idx++] = '\\';
|
||||
buf[idx++] = 'r';
|
||||
} else if (*cp == '\t') {
|
||||
buf[idx++] = '\\';
|
||||
buf[idx++] = 't';
|
||||
} else if (*cp < ' ' || *cp > '~') {
|
||||
const char hex[] = "0123456789ABCDEF";
|
||||
buf[idx++] = '<';
|
||||
buf[idx++] = hex[(*cp >> 4) & 0xF];
|
||||
buf[idx++] = hex[(*cp) & 0xF];
|
||||
buf[idx++] = '>';
|
||||
} else {
|
||||
buf[idx++] = *cp;
|
||||
}
|
||||
cp++;
|
||||
if (idx > 132) {
|
||||
buf[idx++] = '\n';
|
||||
buf[idx++] = '\0';
|
||||
SICSLogWriteFile(buf, eOut, tp);
|
||||
idx = 0;
|
||||
buf[idx++] = '*';
|
||||
buf[idx++] = ':';
|
||||
}
|
||||
}
|
||||
/* Suppress the spurious blank lines caused by trailing newlines */
|
||||
if (idx == 2 && buf[0] == '*' && buf[1] == ':')
|
||||
return;
|
||||
if (idx > 0) {
|
||||
buf[idx++] = '\n';
|
||||
buf[idx++] = '\0';
|
||||
SICSLogWriteFile(buf, eOut, tp);
|
||||
}
|
||||
}
|
||||
|
||||
void SICSLogWriteCode(char *pText, OutCode eOut, char code)
|
||||
{
|
||||
SICSLogWriteTimeCode(pText, eOut, NULL, code);
|
||||
}
|
||||
|
||||
void SICSLogWriteTime(char *pText, OutCode eOut, struct timeval *tp)
|
||||
{
|
||||
SICSLogWriteTimeCode(pText, eOut, tp, 'L');
|
||||
}
|
||||
|
||||
void SICSLogWrite(char *pText, OutCode eOut)
|
||||
{
|
||||
SICSLogWriteTime(pText, eOut, NULL);
|
||||
}
|
||||
|
||||
void SICSLogWriteHexTime(const char *text, int count, OutCode eOut,
|
||||
struct timeval *tp)
|
||||
{
|
||||
const char hex[] = "0123456789ABCDEF";
|
||||
char addr[20], left[80], right[80];
|
||||
char *lp = left;
|
||||
char *rp = right;
|
||||
int i;
|
||||
int duplicates;
|
||||
/* Limit the output */
|
||||
if (count > 1024)
|
||||
count = 1024;
|
||||
duplicates = 0;
|
||||
for (i = 0; i < count; ++i) {
|
||||
if ((i & 0xF) == 0) {
|
||||
if (i > 0) {
|
||||
char line[132];
|
||||
snprintf(line, sizeof(line) - 1, "%-6s: %-49s | %-17s |", addr,
|
||||
left, right);
|
||||
SICSLogWriteTime(line, eOut, tp);
|
||||
}
|
||||
snprintf(addr, sizeof(addr) - 1, "0x%04X", i);
|
||||
while (i >= 16 && i + 16 < count) {
|
||||
if (memcmp(&text[i - 16], &text[i], 16) != 0)
|
||||
break;
|
||||
++duplicates;
|
||||
i += 16;
|
||||
}
|
||||
if (duplicates > 0) {
|
||||
if (duplicates > 1) {
|
||||
char line[132];
|
||||
snprintf(line, sizeof(line) - 1, "%-6s: ... (%d duplicates)",
|
||||
addr, duplicates);
|
||||
SICSLogWriteTime(line, eOut, tp);
|
||||
} else {
|
||||
char line[132];
|
||||
snprintf(line, sizeof(line) - 1, "%-6s: %-49s | %-17s |", addr,
|
||||
left, right);
|
||||
SICSLogWriteTime(line, eOut, tp);
|
||||
}
|
||||
duplicates = 0;
|
||||
}
|
||||
snprintf(addr, sizeof(addr) - 1, "0x%04X", i);
|
||||
lp = left;
|
||||
rp = right;
|
||||
}
|
||||
*lp++ = hex[(text[i] >> 4) & 0xF];
|
||||
*lp++ = hex[(text[i]) & 0xF];
|
||||
*lp++ = ' ';
|
||||
if (text[i] >= ' ' && text[i] <= '~')
|
||||
*rp++ = text[i];
|
||||
else
|
||||
*rp++ = '.';
|
||||
/* if we just did slot 7, insert an extra space */
|
||||
if ((i & 0xF) == 7) {
|
||||
*lp++ = ' ';
|
||||
*rp++ = ' ';
|
||||
}
|
||||
*lp = *rp = '\0';
|
||||
}
|
||||
if (i > 0) {
|
||||
char line[132];
|
||||
snprintf(line, sizeof(line) - 1, "%-6s: %-49s | %-17s |", addr, left,
|
||||
right);
|
||||
SICSLogWriteTime(line, eOut, tp);
|
||||
}
|
||||
}
|
||||
|
||||
void SICSLogWriteHex(const char *text, int count, OutCode eOut)
|
||||
{
|
||||
SICSLogWriteHexTime(text, count, eOut, NULL);
|
||||
}
|
||||
|
||||
void SICSLogTimePrintf(OutCode eOut, struct timeval *tp, const char *fmt,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[256];
|
||||
char *dyn;
|
||||
unsigned int l;
|
||||
int res;
|
||||
|
||||
va_start(ap, fmt);
|
||||
l = vsnprintf(buf, sizeof buf, fmt, ap);
|
||||
va_end(ap);
|
||||
if (l >= sizeof buf) {
|
||||
/* we have probably a C99 conforming snprintf and
|
||||
need a larger buffer
|
||||
*/
|
||||
dyn = malloc(l + 1);
|
||||
if (dyn != NULL) {
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(dyn, l + 1, fmt, ap);
|
||||
va_end(ap);
|
||||
SICSLogWriteTime(dyn, eOut, tp);
|
||||
free(dyn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
SICSLogWriteTime(buf, eOut, tp);
|
||||
return;
|
||||
}
|
||||
|
||||
void SICSLogPrintf(OutCode eOut, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buf[256];
|
||||
char *dyn;
|
||||
unsigned int l;
|
||||
int res;
|
||||
|
||||
va_start(ap, fmt);
|
||||
l = vsnprintf(buf, sizeof buf, fmt, ap);
|
||||
va_end(ap);
|
||||
if (l >= sizeof buf) {
|
||||
/* we have probably a C99 conforming snprintf and
|
||||
need a larger buffer
|
||||
*/
|
||||
dyn = malloc(l + 1);
|
||||
if (dyn != NULL) {
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(dyn, l + 1, fmt, ap);
|
||||
va_end(ap);
|
||||
SICSLogWrite(dyn, eOut);
|
||||
free(dyn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
SICSLogWrite(buf, eOut);
|
||||
return;
|
||||
}
|
||||
|
26
servlog.h
26
servlog.h
@ -16,9 +16,25 @@
|
||||
#define SICSLOG
|
||||
#include "Scommon.h"
|
||||
void SICSLogWrite(char *ptext, OutCode eOut);
|
||||
void SICSLogEnable(int flag);
|
||||
int KillCapture(SConnection * pCon);
|
||||
|
||||
int LogCapture(SConnection * pCon, SicsInterp * pInter, void *pData,
|
||||
int argc, char *argv[]);
|
||||
void SICSLogWriteTime(char *ptext, OutCode eOut, struct timeval *tp);
|
||||
void SICSLogWriteCode(char *ptext, OutCode eOut, char code);
|
||||
void SICSLogWriteTimeCode(char *ptext, OutCode eOut, struct timeval *tp, char code);
|
||||
void SICSLogWriteHex(const char *text, int count, OutCode eOut);
|
||||
void SICSLogWriteHexTime(const char *text, int count, OutCode eOut,
|
||||
struct timeval *tp);
|
||||
#if __GNUC__ > 2
|
||||
#define G_GNUC_PRINTF( format_idx, arg_idx ) \
|
||||
__attribute__((__format__ (__printf__, format_idx, arg_idx)))
|
||||
#else
|
||||
#define G_GNUC_PRINTF( format_idx, arg_idx )
|
||||
#endif
|
||||
void SICSLogPrintf(OutCode eOut, const char *fmt, ...) G_GNUC_PRINTF (2, 3);
|
||||
void SICSLogTimePrintf(OutCode eOut, struct timeval *tp, const char *fmt,
|
||||
...) G_GNUC_PRINTF (3, 4);
|
||||
#undef G_GNUC_PRINTF
|
||||
void SICSLogEnable(int flag);
|
||||
typedef void (*pSICSLogHook)(const char *pText, OutCode eOut, void *pData);
|
||||
char *AddSICSLogHook(pSICSLogHook func, const char *pCodes, void *pData);
|
||||
char *RemSICSLogHook(void *pData);
|
||||
unsigned int GetSICSLogHook(void *pData);
|
||||
#endif
|
||||
|
@ -90,7 +90,7 @@ static int SICSGetCommand(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
}
|
||||
} else {
|
||||
if(v.dataType == HIPTEXT && strstr(v.v.text,"ERROR") != NULL){
|
||||
SCPrintf(pCon,eError,v.v.text);
|
||||
SCPrintf(pCon,eError,"%s",v.v.text);
|
||||
} else {
|
||||
SCPrintf(pCon,eError,"ERROR: value for %s not found", argv[1]);
|
||||
}
|
||||
@ -153,6 +153,7 @@ static int InvokeSICSFunc(void *ms, void *userData)
|
||||
SCsetMacro(pCon,0);
|
||||
if(!status){
|
||||
self->success = 0;
|
||||
SCDeleteConnection(pCon);
|
||||
return MPSTOP;
|
||||
}
|
||||
self->response = strdup(Tcl_GetStringResult(InterpGetTcl(pServ->pSics)));
|
||||
|
4
sicsglobal.c
Normal file
4
sicsglobal.c
Normal file
@ -0,0 +1,4 @@
|
||||
/***************************** Necessary Globals ****************************/
|
||||
|
||||
const char *argv0 = (void*) 0;
|
||||
int isDuringInitialization = 1; /* gets set to zero after initialization */
|
6
sicsglobal.h
Normal file
6
sicsglobal.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef SICSGLOBAL_H
|
||||
#define SICSGLOBAL_H
|
||||
|
||||
extern const char *argv0;
|
||||
extern int isDuringInitialization;
|
||||
#endif
|
427
sicshipadaba.c
427
sicshipadaba.c
@ -435,12 +435,12 @@ typedef struct {
|
||||
int internalID;
|
||||
} HdbCBInfo;
|
||||
|
||||
static Protocol isJSON(SConnection * pCon)
|
||||
static Protocol isJSON(SConnection * pCon, int notify)
|
||||
{
|
||||
char proName[128];
|
||||
void *pData;
|
||||
|
||||
if (SCinMacro(pCon)) {
|
||||
if (notify == 0 && SCinMacro(pCon)) {
|
||||
return normal_protocol;
|
||||
}
|
||||
pData = FindCommandData(pServ->pSics, "protocol", "Protocol");
|
||||
@ -659,7 +659,7 @@ static hdbCallbackReturn SICSNotifyCallback(pHdb node, void *userData,
|
||||
|
||||
GetHdbPath(node,updatePath,sizeof(updatePath));
|
||||
result = CreateDynString(128, 128);
|
||||
if ((protocol = isJSON(cbInfo->pCon)) == 1)
|
||||
if ((protocol = isJSON(cbInfo->pCon, 1)) == 1)
|
||||
outCode = eHdbEvent;
|
||||
else
|
||||
outCode = eEvent;
|
||||
@ -688,8 +688,11 @@ static hdbCallbackReturn SICSNotifyCallback(pHdb node, void *userData,
|
||||
}
|
||||
formatNameValue(protocol, updatePath, GetCharArray(printedData), result,
|
||||
mm->v->dataType);
|
||||
/* SCWrite(cbInfo->pCon, GetCharArray(result), outCode); */
|
||||
#ifdef SITE_ANSTO
|
||||
SCWrite(cbInfo->pCon, GetCharArray(result), outCode);
|
||||
#else
|
||||
SCPureSockWrite(cbInfo->pCon, GetCharArray(result), outCode);
|
||||
#endif
|
||||
DeleteDynString(printedData);
|
||||
} else {
|
||||
formatNameValue(protocol, updatePath, "!!datachange!!", result, HIPTEXT);
|
||||
@ -786,7 +789,7 @@ static hdbCallbackReturn TreeChangeCallback(pHdb node, void *userData,
|
||||
return hdbAbort;
|
||||
}
|
||||
path = GetHipadabaPath(node);
|
||||
if ((protocol = isJSON(cbInfo->pCon)) == 1)
|
||||
if ((protocol = isJSON(cbInfo->pCon, 1)) == 1)
|
||||
outCode = eHdbEvent;
|
||||
else
|
||||
outCode = eEvent;
|
||||
@ -1540,7 +1543,7 @@ pHdb FindHdbParent(char *rootpath, char *relpath, char **namePtr,
|
||||
} else {
|
||||
iret = snprintf(buffer, sizeof buffer, "%s/%s", rootpath, relpath);
|
||||
}
|
||||
if (iret < 0 || iret >= sizeof(buffer)) {
|
||||
if (iret < 0 || iret >= (int) sizeof(buffer)) {
|
||||
SCWrite(pCon, "ERROR: path too long", eError);
|
||||
return NULL;
|
||||
}
|
||||
@ -1652,7 +1655,7 @@ int GetHdbPath(pHdb nodeArg, char *path, size_t pathlen)
|
||||
len = 0;
|
||||
for (node = nodeArg; node != NULL && node != root; node = node->mama) {
|
||||
len += strlen(node->name) + 1;
|
||||
if (len >= pathlen)
|
||||
if (len >= (int) pathlen)
|
||||
return 0; /* buffer overflow (recursive path?) */
|
||||
parent = node;
|
||||
}
|
||||
@ -1669,7 +1672,7 @@ int GetHdbPath(pHdb nodeArg, char *path, size_t pathlen)
|
||||
}
|
||||
l = strlen(sics);
|
||||
len += l;
|
||||
if (len > pathlen)
|
||||
if (len > (int) pathlen)
|
||||
return 0; /* buffer overflow */
|
||||
strncpy(path, sics, l);
|
||||
}
|
||||
@ -2336,6 +2339,71 @@ static int MakeHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int MakeHdbScriptNode(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[])
|
||||
{
|
||||
int type = 0, i, length = 0;
|
||||
char *name = NULL;
|
||||
pHdb parent = NULL;
|
||||
pHdb child = NULL;
|
||||
pHdb current = NULL;
|
||||
char *urgv[] = { "5", NULL };
|
||||
char driver[] = { "hdb" };
|
||||
char buffer[512], buffer2[512];
|
||||
|
||||
|
||||
if (!SCMatchRights(pCon, usMugger)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc < 5) {
|
||||
SCWrite(pCon, "ERROR: not enough arguments to MakeHdbNode", eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* convert datatype
|
||||
*/
|
||||
strtolower(argv[4]);
|
||||
type = convertHdbType(argv[4]);
|
||||
if (type >= 7) {
|
||||
SCWrite(pCon,
|
||||
"ERROR: invalid type requested: none, int, float, text, intar, floatar, intvarar, floatvarar supported",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
if (type > 2) {
|
||||
if (argc < 6) {
|
||||
SCWrite(pCon, "ERROR: array length missing for array data type",
|
||||
eError);
|
||||
return 0;
|
||||
} else {
|
||||
length = atoi(argv[5]);
|
||||
}
|
||||
}
|
||||
|
||||
parent = FindHdbParent(NULL, argv[1], &name, pCon);
|
||||
if (parent == NULL) {
|
||||
return 0; /* error messages written inside FindHdbParent */
|
||||
}
|
||||
child = MakeSICSScriptPar(name, argv[3], argv[2],
|
||||
makeHdbValue(type, length));
|
||||
if (child == NULL) {
|
||||
SCWrite(pCon, "ERROR: out of memory creating node", eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
AddHipadabaChild(parent, child, pCon);
|
||||
/*
|
||||
* have it polled automatically
|
||||
*/
|
||||
addPollObject(poller, pCon, GetHipadabaPath(child), driver, 1, urgv);
|
||||
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
static int isNodeProtected(pHdb node)
|
||||
{
|
||||
@ -2559,7 +2627,7 @@ static int ZipGetHdbNode(SConnection * pCon, SicsInterp * pSics,
|
||||
SCWrite(pCon, "ERROR: out of memory formatting data", eError);
|
||||
return 0;
|
||||
}
|
||||
if ((protocol = isJSON(pCon)) == 1)
|
||||
if ((protocol = isJSON(pCon, 0)) == 1)
|
||||
outCode = eHdbEvent;
|
||||
else
|
||||
outCode = eValue;
|
||||
@ -2604,7 +2672,7 @@ static int ZipReadHdbNode(SConnection * pCon, SicsInterp * pSics,
|
||||
SCWrite(pCon, "ERROR: out of memory formatting data", eError);
|
||||
return 0;
|
||||
}
|
||||
if ((protocol = isJSON(pCon)) == 1)
|
||||
if ((protocol = isJSON(pCon,0)) == 1)
|
||||
outCode = eHdbEvent;
|
||||
else
|
||||
outCode = eValue;
|
||||
@ -2715,13 +2783,17 @@ static int GetHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
}
|
||||
}
|
||||
memset(&newValue, 0, sizeof(hdbValue));
|
||||
GetHipadabaPar(targetNode, &newValue, pCon);
|
||||
/* ffr XXX I expect if status=0 then we don't have a valid value
|
||||
Original code was causing a segfault for hdb text nodes
|
||||
*/
|
||||
if (0 == GetHipadabaPar(targetNode, &newValue, pCon))
|
||||
return 0;
|
||||
parData = formatValue(newValue, targetNode);
|
||||
if (parData == NULL) {
|
||||
SCWrite(pCon, "ERROR: out of memory formatting data", eError);
|
||||
return 0;
|
||||
}
|
||||
if ((protocol = isJSON(pCon)) == 1)
|
||||
if ((protocol = isJSON(pCon, 0)) == 1)
|
||||
outCode = eHdbEvent;
|
||||
else
|
||||
outCode = eValue;
|
||||
@ -2759,13 +2831,14 @@ static int GetHdbVal(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
return 0;
|
||||
}
|
||||
memset(&newValue, 0, sizeof(hdbValue));
|
||||
GetHipadabaPar(targetNode, &newValue, pCon);
|
||||
if (0 == GetHipadabaPar(targetNode, &newValue, pCon))
|
||||
return 0;
|
||||
parData = formatValue(newValue, targetNode);
|
||||
if (parData == NULL) {
|
||||
SCWrite(pCon, "ERROR: out of memory formatting data", eError);
|
||||
return 0;
|
||||
} else {
|
||||
if ((protocol = isJSON(pCon)) == 1)
|
||||
if ((protocol = isJSON(pCon, 0)) == 1)
|
||||
outCode = eHdbEvent;
|
||||
else
|
||||
outCode = eValue;
|
||||
@ -2777,6 +2850,37 @@ static int GetHdbVal(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int GetHdbValIgnoreError(
|
||||
SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[])
|
||||
{
|
||||
pHdb targetNode = NULL;
|
||||
pDynString parData = NULL;
|
||||
int protocol, outCode;
|
||||
|
||||
if (argc != 2) {
|
||||
SCWrite(pCon, "ERROR: syntax must be: hvali <path>", eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
targetNode = FindHdbNode(NULL, argv[1], pCon);
|
||||
if (targetNode == NULL) {
|
||||
return 0;
|
||||
}
|
||||
parData = formatValue(targetNode->value, targetNode);
|
||||
if (parData == NULL) {
|
||||
SCWrite(pCon, "ERROR: out of memory formatting data", eError);
|
||||
return 0;
|
||||
}
|
||||
if ((protocol = isJSON(pCon, 0)) == 1)
|
||||
outCode = eHdbEvent;
|
||||
else
|
||||
outCode = eValue;
|
||||
SCWrite(pCon, GetCharArray(parData), outCode);
|
||||
DeleteDynString(parData);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int countChildren(pHdb node)
|
||||
{
|
||||
@ -3071,7 +3175,7 @@ static int ListHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
} else if (strcmp(argv[1], "-cli") == 0) {
|
||||
listData = formatClientList(node);
|
||||
} else {
|
||||
if ((protocol = isJSON(pCon)) == 1) {
|
||||
if ((protocol = isJSON(pCon, 0)) == 1) {
|
||||
listData = formatJSONList(node);
|
||||
outCode = eHdbEvent;
|
||||
} else {
|
||||
@ -3151,6 +3255,62 @@ static int RemoveHdbCallback(SConnection * pCon, SicsInterp * pSics,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int LinkHdbNode(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
pHdb node = NULL;
|
||||
char buffer[256];
|
||||
pObjectDescriptor pDes = NULL;
|
||||
|
||||
if (argc < 3) {
|
||||
SCWrite(pCon, "ERROR: need path and object name to link", eError);
|
||||
return 0;
|
||||
}
|
||||
if (!SCMatchRights(pCon, usMugger)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
node = GetHipadabaNode(root, argv[1]);
|
||||
if (node == NULL) {
|
||||
snprintf(buffer, 255, "ERROR: path %s NOT found!", argv[1]);
|
||||
SCWrite(pCon, buffer, eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pDes = FindCommandDescriptor(pSics, argv[2]);
|
||||
if (pDes == NULL) {
|
||||
snprintf(buffer, 255, "ERROR: failed to find object %s", argv[2]);
|
||||
SCWrite(pCon, buffer, eError);
|
||||
return 0;
|
||||
}
|
||||
if (pDes->parNode == NULL) {
|
||||
snprintf(buffer, 255,
|
||||
"ERROR: Object %s does not use Hipadaba natively and thus cannot be linked",
|
||||
argv[2]);
|
||||
SCWrite(pCon, buffer, eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pDes->parNode->mama != NULL) {
|
||||
snprintf(buffer, 255,
|
||||
"ERROR: Object %s is already linked somewhere else", argv[2]);
|
||||
SCWrite(pCon, buffer, eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
AddHipadabaChild(node, pDes->parNode, pCon);
|
||||
|
||||
if (argc > 3) {
|
||||
if (pDes->parNode->name != NULL) {
|
||||
free(pDes->parNode->name);
|
||||
}
|
||||
pDes->parNode->name = strdup(argv[3]);
|
||||
}
|
||||
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int isArrayNode(pHdb node)
|
||||
{
|
||||
@ -3599,9 +3759,9 @@ static hdbCallbackReturn CommandSetCallback(pHdb node, void *userData,
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
SendHdbStatusMessage(node, "start");
|
||||
// SendHdbStatusMessage(node,"start");
|
||||
status = HDBInvoke(pCon, pServ->pSics, GetCharArray(cmd));
|
||||
SendHdbStatusMessage(node, "stop");
|
||||
// SendHdbStatusMessage(node,"stop");
|
||||
DeleteDynString(cmd);
|
||||
if (status == 1) {
|
||||
return hdbContinue;
|
||||
@ -3632,6 +3792,60 @@ static hdbCallbackReturn CommandGetCallback(pHdb node, void *userData,
|
||||
return hdbContinue;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int SicsCommandNode(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[])
|
||||
{
|
||||
char *name = NULL;
|
||||
pHdbCallback kalle = NULL;
|
||||
pHdb parent = NULL, node = NULL;
|
||||
|
||||
if (argc < 3) {
|
||||
SCWrite(pCon, "ERROR: insufficent number of arguments to hcommand",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
if (!SCMatchRights(pCon, usMugger)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
parent = FindHdbParent(NULL, argv[1], &name, pCon);
|
||||
if (parent == NULL) {
|
||||
return 0; /* error message already written */
|
||||
}
|
||||
node = MakeHipadabaNode(name, HIPTEXT, 1);
|
||||
if (node == NULL) {
|
||||
SCWrite(pCon, "ERROR: out of memory in hcommand", eError);
|
||||
return 0;
|
||||
}
|
||||
node->value.v.text = strdup(argv[2]);
|
||||
node->value.arrayLength = strlen(argv[2]);
|
||||
SetHdbProperty(node, "sicscommand", argv[2]);
|
||||
// Set privillege of the node
|
||||
if (argc > 3) {
|
||||
SetHdbProperty(node, "priv", argv[3]);
|
||||
}
|
||||
|
||||
kalle = MakeHipadabaCallback(CommandSetCallback, NULL, NULL);
|
||||
if (kalle == NULL) {
|
||||
SCWrite(pCon, "ERROR: out of memory in hcommand", eError);
|
||||
return 0;
|
||||
}
|
||||
AppendHipadabaCallback(node, kalle);
|
||||
|
||||
kalle = MakeHipadabaCallback(CommandGetCallback, NULL, NULL);
|
||||
if (kalle == NULL) {
|
||||
SCWrite(pCon, "ERROR: out of memory in hcommand", eError);
|
||||
return 0;
|
||||
}
|
||||
AppendHipadabaCallback(node, kalle);
|
||||
|
||||
AddHipadabaChild(parent, node, pCon);
|
||||
|
||||
SCSendOK(pCon);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*======================= Property Functions ================================*/
|
||||
static int SetSICSHdbProperty(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[])
|
||||
@ -3681,6 +3895,30 @@ static int DelSICSHdbProperty(SConnection * pCon, SicsInterp * pSics,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int HasSICSHdbProperty(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[])
|
||||
{
|
||||
pHdb targetNode = NULL;
|
||||
|
||||
if (argc < 3) {
|
||||
SCWrite(pCon, "ERROR: need path key as parameters", eError);
|
||||
return 0;
|
||||
}
|
||||
targetNode = FindHdbNode(NULL, argv[1], pCon);
|
||||
if (targetNode == NULL) {
|
||||
SCWrite(pCon, "ERROR: node not found", eError);
|
||||
return 0;
|
||||
}
|
||||
if (HasHdbProperty(targetNode, argv[2])) {
|
||||
SCPrintf(pCon, eValue, "%s", "true");
|
||||
return 1;
|
||||
} else {
|
||||
SCPrintf(pCon, eValue, "%s", "false");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int GetSICSHdbProperty(SConnection * pCon, SicsInterp * pSics,
|
||||
void *pData, int argc, char *argv[])
|
||||
@ -3741,10 +3979,18 @@ static int ListSICSHdbProperty(SConnection * pCon, SicsInterp * pSics,
|
||||
char buffer[512];
|
||||
const char *pKey = NULL;
|
||||
pDynString data = NULL;
|
||||
int genTclList = 0;
|
||||
|
||||
if (argc < 2) {
|
||||
SCWrite(pCon, "ERROR: need path as parameter", eError);
|
||||
return 0;
|
||||
} else if (argc == 3) {
|
||||
if (strncasecmp(argv[2], "tcl", 3) == 0)
|
||||
genTclList = 1;
|
||||
if (strncasecmp(argv[2], "tclesc", 6) == 0)
|
||||
genTclList |= 2;
|
||||
if (strncasecmp(argv[2], "tclnam", 6) == 0)
|
||||
genTclList |= 4;
|
||||
}
|
||||
targetNode = FindHdbNode(NULL, argv[1], pCon);
|
||||
if (targetNode == NULL) {
|
||||
@ -3759,9 +4005,24 @@ static int ListSICSHdbProperty(SConnection * pCon, SicsInterp * pSics,
|
||||
InitHdbPropertySearch(targetNode);
|
||||
while ((pKey = GetNextHdbProperty(targetNode, buffer, 511)) != NULL) {
|
||||
DynStringConcat(data, (char *) pKey);
|
||||
DynStringConcat(data, "=");
|
||||
DynStringConcat(data, buffer);
|
||||
DynStringConcat(data, "\n");
|
||||
if (genTclList) {
|
||||
char *bp;
|
||||
DynStringConcatChar(data, ' ');
|
||||
if (genTclList & 4)
|
||||
continue;
|
||||
DynStringConcatChar(data, '{');
|
||||
for (bp = buffer; *bp; ++bp) {
|
||||
if (genTclList & 2 && (*bp == '{' || *bp == '}'))
|
||||
DynStringConcatChar(data, '\\');
|
||||
DynStringConcatChar(data, *bp);
|
||||
}
|
||||
DynStringConcatChar(data, '}');
|
||||
DynStringConcatChar(data, ' ');
|
||||
} else {
|
||||
DynStringConcat(data, "=");
|
||||
DynStringConcat(data, buffer);
|
||||
DynStringConcat(data, "\n");
|
||||
}
|
||||
}
|
||||
SCWrite(pCon, GetCharArray(data), eValue);
|
||||
DeleteDynString(data);
|
||||
@ -3789,24 +4050,94 @@ static int CallNotify(SConnection * pCon, SicsInterp * pSics,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static pHdb matchHdbProp(pHdb root, char *propname, char *buffer)
|
||||
static int ANSTO_ListSICSHdbProperty(SConnection * pCon,
|
||||
SicsInterp * pSics, void *pData,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
char value[1024];
|
||||
pHdb targetNode = NULL;
|
||||
char buffer[512], *globPtr = NULL;
|
||||
int cmpSize = 0;
|
||||
const char *pKey = NULL;
|
||||
pDynString data = NULL;
|
||||
|
||||
if (argc < 3) {
|
||||
SCWrite(pCon, "ERROR: need path and search string as parameters",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
targetNode = FindHdbNode(NULL, argv[1], pCon);
|
||||
if (targetNode == NULL) {
|
||||
SCWrite(pCon, "ERROR: node not found", eError);
|
||||
return 0;
|
||||
}
|
||||
data = CreateDynString(64, 64);
|
||||
if (data == NULL) {
|
||||
SCWrite(pCon, "ERROR: out of memory in ListSICSHdbProperty", eError);
|
||||
return 0;
|
||||
}
|
||||
InitHdbPropertySearch(targetNode);
|
||||
|
||||
/* Allow simple glob matches with '*' as a suffix
|
||||
Eg hfindprop /hpath @*
|
||||
*/
|
||||
if ((globPtr = index(argv[2], '*')) != NULL) {
|
||||
*globPtr = '\0';
|
||||
}
|
||||
cmpSize = strlen(argv[2]);
|
||||
while ((pKey = GetNextHdbProperty(targetNode, buffer, 511)) != NULL) {
|
||||
if (strncasecmp(argv[2], pKey, cmpSize) == 0) {
|
||||
DynStringConcat(data, (char *) pKey);
|
||||
DynStringConcat(data, " ");
|
||||
DynStringConcat(data, buffer);
|
||||
DynStringConcat(data, "\n");
|
||||
}
|
||||
}
|
||||
SCWrite(pCon, GetCharArray(data), eValue);
|
||||
DeleteDynString(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static pHdb matchHdbProp(pHdb root, char *propname, char *buffer,
|
||||
pDynString result, int invertmatch)
|
||||
{
|
||||
char value[1024], *path = NULL;
|
||||
pHdb current = NULL, search;
|
||||
|
||||
memset(value, 0, 1024);
|
||||
if (GetHdbProperty(root, propname, value, 1023) == 1) {
|
||||
if (strcmp(buffer, "*") == 0) {
|
||||
if (GetHdbProperty(root, propname, value, 1023) == 1) {
|
||||
if (!invertmatch) {
|
||||
path = GetHipadabaPath(root);
|
||||
DynStringConcat(result, path);
|
||||
DynStringConcat(result, "\n");
|
||||
free(path);
|
||||
}
|
||||
} else if (invertmatch) {
|
||||
path = GetHipadabaPath(root);
|
||||
DynStringConcat(result, path);
|
||||
DynStringConcat(result, "\n");
|
||||
free(path);
|
||||
}
|
||||
} else if (GetHdbProperty(root, propname, value, 1023) == 1) {
|
||||
if (strstr(buffer, value) != NULL) {
|
||||
return root;
|
||||
if (!invertmatch) {
|
||||
path = GetHipadabaPath(root);
|
||||
DynStringConcat(result, path);
|
||||
DynStringConcat(result, "\n");
|
||||
free(path);
|
||||
}
|
||||
} else if (invertmatch) {
|
||||
path = GetHipadabaPath(root);
|
||||
DynStringConcat(result, path);
|
||||
DynStringConcat(result, "\n");
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
current = root->child;
|
||||
while (current != NULL) {
|
||||
search = matchHdbProp(current, propname, buffer);
|
||||
if (search != NULL) {
|
||||
return search;
|
||||
}
|
||||
search =
|
||||
matchHdbProp(current, propname, buffer, result, invertmatch);
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
@ -3819,6 +4150,8 @@ static int MatchHdbProperty(SConnection * pCon, SicsInterp * pSics,
|
||||
pHdb root = NULL;
|
||||
pHdb foundNode = NULL;
|
||||
char buffer[1024], *path = NULL;
|
||||
int node = 1, prop = 2, propval = 3, invertmatch = 0;
|
||||
pDynString matchList = NULL;
|
||||
|
||||
if (argc < 4) {
|
||||
SCWrite(pCon,
|
||||
@ -3826,25 +4159,29 @@ static int MatchHdbProperty(SConnection * pCon, SicsInterp * pSics,
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
if (argc >= 5) {
|
||||
if (strcasecmp(argv[1], "invert") == 0) {
|
||||
invertmatch = 1;
|
||||
node++;
|
||||
prop++;
|
||||
propval++;
|
||||
}
|
||||
}
|
||||
memset(buffer, 0, 1024);
|
||||
Arg2Text(argc - 3, &argv[3], buffer, 1023);
|
||||
root = GetHipadabaNode(GetHipadabaRoot(), argv[1]);
|
||||
Arg2Text(argc - propval, &argv[propval], buffer, 1023);
|
||||
root = GetHipadabaNode(GetHipadabaRoot(), argv[node]);
|
||||
if (root == NULL) {
|
||||
SCWrite(pCon, "ERROR: start node for search not found", eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
strtolower(argv[2]);
|
||||
strtolower(argv[prop]);
|
||||
strtolower(buffer);
|
||||
foundNode = matchHdbProp(root, argv[2], buffer);
|
||||
|
||||
if (foundNode == NULL) {
|
||||
SCWrite(pCon, "NONE", eValue);
|
||||
} else {
|
||||
path = GetHipadabaPath(foundNode);
|
||||
SCWrite(pCon, path, eValue);
|
||||
free(path);
|
||||
}
|
||||
matchList = CreateDynString(128, 128);
|
||||
foundNode =
|
||||
matchHdbProp(root, argv[prop], buffer, matchList, invertmatch);
|
||||
SCWrite(pCon, GetCharArray(matchList), eValue);
|
||||
DeleteDynString(matchList);
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@ -3953,7 +4290,9 @@ int InstallSICSHipadaba(SConnection * pCon, SicsInterp * pSics,
|
||||
{
|
||||
|
||||
root = MakeHipadabaNode("/", HIPNONE, 0);
|
||||
AddCommand(pSics, "hmake", MakeHdbNode, NULL, NULL);
|
||||
AddCommand(pSics, "hfactory", HdbNodeFactory, NULL, NULL);
|
||||
AddCommand(pSics, "hmakescript", MakeHdbScriptNode, NULL, NULL);
|
||||
AddCommand(pSics, "hattach", SICSHdbAdapter, NULL, NULL);
|
||||
AddCommand(pSics, "hsubsamplehm", HdbSubSample, NULL, NULL);
|
||||
AddCommand(pSics, "hdel", DeleteHdbNode, NULL, NULL);
|
||||
@ -3961,22 +4300,26 @@ int InstallSICSHipadaba(SConnection * pCon, SicsInterp * pSics,
|
||||
AddCommand(pSics, "hupdate", UpdateHdbNode, NULL, NULL);
|
||||
AddCommand(pSics, "hget", GetHdbNode, NULL, NULL);
|
||||
AddCommand(pSics, "hval", GetHdbVal, NULL, NULL);
|
||||
AddCommand(pSics, "hvali", GetHdbValIgnoreError, NULL, NULL);
|
||||
AddCommand(pSics, "hzipget", ZipGetHdbNode, NULL, NULL);
|
||||
AddCommand(pSics, "hzipread", ZipReadHdbNode, NULL, NULL);
|
||||
AddCommand(pSics, "hbinread", BinReadHdbNode, NULL, NULL);
|
||||
AddCommand(pSics, "hlist", ListHdbNode, NULL, NULL);
|
||||
AddCommand(pSics, "hnotify", AutoNotifyHdbNode, NULL, NULL);
|
||||
AddCommand(pSics, "hdelcb", RemoveHdbCallback, NULL, NULL);
|
||||
AddCommand(pSics, "hlink", LinkHdbNode, NULL, NULL);
|
||||
AddCommand(pSics, "hinfo", HdbNodeInfo, NULL, NULL);
|
||||
/* AddCommand(pSics, "hval", HdbNodeVal, NULL, NULL);*/
|
||||
AddCommand(pSics, "hchain", ChainHdbNode, NULL, NULL);
|
||||
AddCommand(pSics, "hcommand", SicsCommandNode, NULL, NULL);
|
||||
AddCommand(pSics, "harray", HdbArrayNode, NULL, NULL);
|
||||
AddCommand(pSics, "hsetprop", SetSICSHdbProperty, NULL, NULL);
|
||||
AddCommand(pSics, "hdelprop", DelSICSHdbProperty, NULL, NULL);
|
||||
AddCommand(pSics, "hgetprop", GetSICSHdbProperty, NULL, NULL);
|
||||
AddCommand(pSics, "hgetpropval", GetSICSHdbPropertyVal, NULL, NULL);
|
||||
AddCommand(pSics, "hmatchprop", MatchHdbProperty, NULL, NULL);
|
||||
AddCommand(pSics, "hpropexists", HasSICSHdbProperty, NULL, NULL);
|
||||
AddCommand(pSics, "hlistprop", ListSICSHdbProperty, NULL, NULL);
|
||||
AddCommand(pSics, "hfindprop", ANSTO_ListSICSHdbProperty, NULL, NULL);
|
||||
AddCommand(pSics, "hcallnotify",CallNotify, NULL, NULL);
|
||||
AddCommand(pSics, "haddcheck",AddCheck, NULL, NULL);
|
||||
AddCommand(pSics, "hscriptnotify",AddScriptNotify, NULL, NULL);
|
||||
|
27
sicslist.c
27
sicslist.c
@ -169,6 +169,18 @@ static int printObjectData(SConnection * pCon, pDummy obj, char *key)
|
||||
}
|
||||
}
|
||||
|
||||
static int existsObjectData(SConnection * pCon, pDummy obj, char *key)
|
||||
{
|
||||
char *ptr = NULL;
|
||||
ptr = IFindOption(obj->pDescriptor->pKeys, key);
|
||||
if (ptr != NULL)
|
||||
SCPrintf(pCon, eValue, "%s", "true");
|
||||
else
|
||||
SCPrintf(pCon, eValue, "%s", "false");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
* this function implements a set on top of a list. This means that
|
||||
* the list is first searched for the occurence of name. name is only
|
||||
@ -518,6 +530,21 @@ int SicsList(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "exists") == 0) {
|
||||
if (argc < 4) {
|
||||
SCWrite(pCon, "ERROR: not enough arguments", eError);
|
||||
return 0;
|
||||
} else {
|
||||
pCom = FindCommand(pSics, argv[2]);
|
||||
if (pCom == NULL) {
|
||||
SCWrite(pCon, "ERROR: Object doesn't exist", eError);
|
||||
return 0;
|
||||
} else
|
||||
return existsObjectData(pCon, (pDummy) pCom->pData, argv[3]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* object properties
|
||||
*/
|
||||
|
@ -477,7 +477,6 @@ int InvokeSICSOBJ(SConnection * pCon, SicsInterp * pSics, void *pData,
|
||||
status = GetHdbProperty(parNode,"geterror",buffer,sizeof(buffer));
|
||||
if (status == 1 && strstr(buffer,"none") == NULL){
|
||||
SCPrintf(pCon,eValue,"ERROR: %s on last read of %s", buffer, argv[0]);
|
||||
SCPrintf(pCon,eValue,"%s = -99999", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
status = GetHipadabaPar(parNode, &data, pCon);
|
||||
|
@ -51,7 +51,8 @@ double DoubleTime(void)
|
||||
{
|
||||
struct timeval now;
|
||||
/* the resolution of this function is usec, if the machine supports this
|
||||
and the mantissa of a double is 51 bits or more (31 for sec and 20 for mic$
|
||||
and the mantissa of a double is 51 bits or more (31 bits for seconds
|
||||
and 20 for microseconds)
|
||||
*/
|
||||
gettimeofday(&now, NULL);
|
||||
return now.tv_sec + now.tv_usec / 1e6;
|
||||
|
8
sicvar.c
8
sicvar.c
@ -245,7 +245,7 @@ int VarSetFloat(pSicsVariable self, float fNew, int iUserRights)
|
||||
|
||||
if (self->iAccessCode < iUserRights) {
|
||||
return 0;
|
||||
} else {
|
||||
} else if (self->fVal != fNew) {
|
||||
self->fVal = fNew;
|
||||
InvokeCallBack(self->pCall, VALUECHANGE, self);
|
||||
tracePar(self->name,"%f",fNew);
|
||||
@ -261,7 +261,7 @@ int VarSetInt(pSicsVariable self, int iNew, int iUserRights)
|
||||
|
||||
if (self->iAccessCode < iUserRights) {
|
||||
return 0;
|
||||
} else {
|
||||
} else if (self->iVal != iNew) {
|
||||
self->iVal = iNew;
|
||||
InvokeCallBack(self->pCall, VALUECHANGE, self);
|
||||
tracePar(self->name,"%d",iNew);
|
||||
@ -277,7 +277,7 @@ int VarSetText(pSicsVariable self, char *pNew, int iUserRights)
|
||||
|
||||
if (self->iAccessCode < iUserRights) {
|
||||
return 0;
|
||||
} else {
|
||||
} else if (self->text && strcmp(self->text, pNew)) {
|
||||
if (self->text) {
|
||||
free(self->text);
|
||||
}
|
||||
@ -461,7 +461,7 @@ int VarWrapper(SConnection * pCon, SicsInterp * pInterp, void *pData,
|
||||
return 1;
|
||||
case veFloat:
|
||||
VarGetFloat(pVar, &fVal);
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "%s = %f", argv[0], fVal);
|
||||
snprintf(pBueffel,sizeof(pBueffel)-1, "%s = %#g", argv[0], fVal);
|
||||
SCWrite(pCon, pBueffel, eValue);
|
||||
DeleteTokenList(pList);
|
||||
return 1;
|
||||
|
@ -244,6 +244,12 @@ static int SimSetPar(void *self, SConnection * pCon, char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SimGetTextPar(void *pData, char *name, char *textPar)
|
||||
{
|
||||
snprintf(textPar, 8, "unknown");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void KillSIM(void *pData)
|
||||
{
|
||||
@ -336,6 +342,7 @@ MotorDriver *CreateSIM(SConnection * pCon, int argc, char *argv[])
|
||||
pDriv->fSpeed = .01;
|
||||
pDriv->iTime = 0;
|
||||
pDriv->KillPrivate = KillSIM;
|
||||
pDriv->GetDriverTextPar = SimGetTextPar;
|
||||
|
||||
/* check for optional speed paramter */
|
||||
pCurrent = pCurrent->pNext;
|
||||
|
1
simidx.h
1
simidx.h
@ -85,6 +85,7 @@ int SimIdxRun();
|
||||
* \param errCode pointer to an integer error code
|
||||
* \param error A text buffer to hold a description of the error
|
||||
* \param errLen The length of error
|
||||
*/
|
||||
void SimIdxGetError(int *errCode, char *error, int errLen);
|
||||
|
||||
/**
|
||||
|
2
sinfox.h
2
sinfox.h
@ -56,7 +56,7 @@ char *pDeviceTypes[25] = {
|
||||
"connection",
|
||||
"crystalselector",
|
||||
"environment monitor",
|
||||
"environment controller",
|
||||
"environment_controller",
|
||||
"gpib",
|
||||
"hklscan",
|
||||
"hmcontrol",
|
||||
|
@ -450,7 +450,7 @@ static int SymRefCmd(pSICSOBJ self, SConnection * pCon, pHdb commandNode,
|
||||
hkl[2] = equiv.l[i];
|
||||
if (priv->diffractometer->
|
||||
calculateSettings(priv->diffractometer, hkl, settings) == 1) {
|
||||
snprintf(buffer, 512, "%d,%d,%d", equiv.h[i], equiv.k[i],
|
||||
snprintf(buffer, sizeof(buffer), "%d,%d,%d", equiv.h[i], equiv.k[i],
|
||||
equiv.l[i]);
|
||||
SCWrite(pCon, buffer, eValue);
|
||||
return 1;
|
||||
|
322
stack_trace.c
Normal file
322
stack_trace.c
Normal file
@ -0,0 +1,322 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "dynstring.h"
|
||||
#include "sics.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static const char* timestamp() {
|
||||
static char ts[80];
|
||||
int year, month, day;
|
||||
int hour, min, sec, usec;
|
||||
struct timeval tv;
|
||||
struct tm *time;
|
||||
gettimeofday(&tv, NULL);
|
||||
time = localtime(&tv.tv_sec);
|
||||
year = 1900 + time->tm_year;
|
||||
month = time->tm_mon + 1;
|
||||
day = time->tm_mday;
|
||||
hour = time->tm_hour;
|
||||
min = time->tm_min;
|
||||
sec = time->tm_sec;
|
||||
usec = (int) tv.tv_usec;
|
||||
snprintf(ts, 80, "%04d%02d%02d%02d%02d%02d",
|
||||
year, month, day, hour, min, sec);
|
||||
return ts;
|
||||
}
|
||||
|
||||
#ifdef SICS_HAS_BACKTRACE
|
||||
void stack_trace_backtrace() {
|
||||
void *array[STRACE_SIZE];
|
||||
size_t stack_size;
|
||||
size_t i;
|
||||
char **strings;
|
||||
char buffer[1024];
|
||||
pDynString s = CreateDynString(1000, 100);
|
||||
|
||||
stack_size = backtrace(array, STRACE_SIZE);
|
||||
strings = backtrace_symbols(array, stack_size);
|
||||
for (i = 0; i < stack_size; ++i) {
|
||||
snprintf(buffer, 1024, "%p: %s\n", array[i], strings[i]);
|
||||
DynStringConcat(s, buffer);
|
||||
}
|
||||
free(strings);
|
||||
|
||||
SICSLogWrite(GetCharArray(s), eLogError);
|
||||
DeleteDynString(s);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SICS_HAS_BFD
|
||||
#include <bfd.h>
|
||||
#define STRACE_SIZE 64
|
||||
|
||||
/* globals retained across calls to resolve. */
|
||||
static bfd* abfd = 0;
|
||||
static asymbol **syms = 0;
|
||||
static asection *text = 0;
|
||||
static void resolve(void *address, char *buffer, int buf_len) {
|
||||
if (!abfd) {
|
||||
char ename[1024];
|
||||
int l = readlink("/proc/self/exe",ename,sizeof(ename));
|
||||
if (l == -1) {
|
||||
perror("failed to find executable\n");
|
||||
return;
|
||||
}
|
||||
ename[l] = 0;
|
||||
|
||||
bfd_init();
|
||||
|
||||
abfd = bfd_openr(ename, 0);
|
||||
if (!abfd) {
|
||||
perror("bfd_openr failed: ");
|
||||
return;
|
||||
}
|
||||
|
||||
/* oddly, this is required for it to work... */
|
||||
bfd_check_format(abfd,bfd_object);
|
||||
|
||||
unsigned storage_needed = bfd_get_symtab_upper_bound(abfd);
|
||||
syms = (asymbol **) malloc(storage_needed);
|
||||
unsigned cSymbols = bfd_canonicalize_symtab(abfd, syms);
|
||||
|
||||
text = bfd_get_section_by_name(abfd, ".text");
|
||||
}
|
||||
|
||||
long offset = ((long)address) - text->vma;
|
||||
if (offset > 0) {
|
||||
const char *file;
|
||||
const char *func;
|
||||
unsigned line;
|
||||
if (bfd_find_nearest_line(abfd, text, syms, offset, &file, &func, &line) && file)
|
||||
snprintf(buffer, buf_len, "file: %s, line: %u, func %s\n",file,line,func);
|
||||
}
|
||||
}
|
||||
|
||||
void stack_trace_bfd() {
|
||||
void *array[STRACE_SIZE];
|
||||
size_t stack_size;
|
||||
size_t i;
|
||||
char buffer[1024];
|
||||
pDynString s = CreateDynString(1000, 100);
|
||||
|
||||
stack_size = backtrace(array, STRACE_SIZE);
|
||||
for (i = 0; i < stack_size; ++i) {
|
||||
resolve(array[i], buffer, 1024);
|
||||
DynStringConcat(s, buffer);
|
||||
}
|
||||
SICSLogWrite(GetCharArray(s), eLogError);
|
||||
DeleteDynString(s);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SICS_HAS_GDB
|
||||
void stack_trace_gdb() {
|
||||
int pipefd[2];
|
||||
char pid_buf[30];
|
||||
sprintf(pid_buf, "%d", getpid());
|
||||
char name_buf[512];
|
||||
name_buf[readlink("/proc/self/exe", name_buf, 511)]=0;
|
||||
if (pipe(pipefd) == -1) {
|
||||
perror("pipe");
|
||||
abort();
|
||||
}
|
||||
int child_pid = fork();
|
||||
if (child_pid == -1) {
|
||||
perror("fork");
|
||||
abort();
|
||||
}
|
||||
if (!child_pid) {
|
||||
close(pipefd[0]);
|
||||
dup2(pipefd[1], 1); /* redirect stdout to pipe */
|
||||
dup2(pipefd[1], 2); /* redirect stderr to pipe */
|
||||
fprintf(stdout,"stack trace for %s pid=%s\n",name_buf,pid_buf);
|
||||
fflush(stdout);
|
||||
execlp("gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", "bt", name_buf, pid_buf, NULL);
|
||||
abort(); /* If gdb failed to start */
|
||||
} else {
|
||||
char buff;
|
||||
pDynString s = CreateDynString(100, 100);
|
||||
close(pipefd[1]);
|
||||
while (read(pipefd[0], &buff, 1) > 0) {
|
||||
DynStringConcatChar(s, buff);
|
||||
}
|
||||
SICSLogWrite(GetCharArray(s), eLogError);
|
||||
DeleteDynString(s);
|
||||
close(pipefd[0]);
|
||||
waitpid(child_pid,NULL,0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SICS_HAS_ABORT
|
||||
void stack_trace_abort() {
|
||||
int child_pid = fork();
|
||||
if (child_pid == -1) {
|
||||
perror("fork");
|
||||
abort();
|
||||
}
|
||||
if (!child_pid) {
|
||||
/* Dump core */
|
||||
abort();
|
||||
} else {
|
||||
waitpid(child_pid,NULL,0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t get_size_of_files(char *glob) {
|
||||
int pipefd[2];
|
||||
if (pipe(pipefd) == -1) {
|
||||
perror("pipe");
|
||||
abort();
|
||||
}
|
||||
int child_pid = fork();
|
||||
if (child_pid == -1) {
|
||||
perror("fork");
|
||||
abort();
|
||||
}
|
||||
if (!child_pid) {
|
||||
char cmd[120];
|
||||
close(pipefd[0]);
|
||||
dup2(pipefd[1], 1); /* redirect stdout to pipe */
|
||||
dup2(pipefd[1], 2); /* redirect stderr to pipe */
|
||||
snprintf(cmd, sizeof(cmd)-1, "du -s %s", glob);
|
||||
execlp("bash", "bash", "-c", cmd, NULL);
|
||||
exit(0); /* If gdb failed to start */
|
||||
} else {
|
||||
size_t total_size = 0;
|
||||
char buff;
|
||||
pDynString s = CreateDynString(100, 100);
|
||||
close(pipefd[1]);
|
||||
while (read(pipefd[0], &buff, 1) > 0) {
|
||||
DynStringConcatChar(s, buff);
|
||||
if (buff == '\n') {
|
||||
SICSLogWrite(GetCharArray(s), eLog);
|
||||
int this_size = atoi(GetCharArray(s));
|
||||
total_size += this_size;
|
||||
DynStringClear(s);
|
||||
}
|
||||
}
|
||||
if (GetDynStringLength(s) > 0)
|
||||
SICSLogWrite(GetCharArray(s), eLogError);
|
||||
DeleteDynString(s);
|
||||
close(pipefd[0]);
|
||||
waitpid(child_pid, NULL, 0);
|
||||
SICSLogPrintf(eLog, "Total size of files \"%s\" is %ldK", glob, total_size);
|
||||
return total_size;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_stack_trace(int full, int dump) {
|
||||
int pipefd[2];
|
||||
char pid_buf[30];
|
||||
sprintf(pid_buf, "%d", getpid());
|
||||
char name_buf[512];
|
||||
name_buf[readlink("/proc/self/exe", name_buf, 511)]=0;
|
||||
if (pipe(pipefd) == -1) {
|
||||
perror("pipe");
|
||||
abort();
|
||||
}
|
||||
int child_pid = fork();
|
||||
if (child_pid == -1) {
|
||||
perror("fork");
|
||||
abort();
|
||||
}
|
||||
if (!child_pid) {
|
||||
char *bt;
|
||||
close(pipefd[0]);
|
||||
dup2(pipefd[1], 1); /* redirect stdout to pipe */
|
||||
dup2(pipefd[1], 2); /* redirect stderr to pipe */
|
||||
fprintf(stdout, "stack trace for %s pid=%s\n", name_buf, pid_buf);
|
||||
fflush(stdout);
|
||||
if (full)
|
||||
bt = "bt full";
|
||||
else
|
||||
bt = "bt";
|
||||
if (dump) {
|
||||
char gen_buf[128];
|
||||
snprintf(gen_buf, sizeof(gen_buf)-1, "generate-core-file /tmp/core.%s.%s", timestamp(), pid_buf);
|
||||
execlp("gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", bt, "-ex", gen_buf, name_buf, pid_buf, NULL);
|
||||
} else {
|
||||
execlp("gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", bt, name_buf, pid_buf, NULL);
|
||||
}
|
||||
fprintf(stdout, "gdb failed to start for %s pid=%d\n", name_buf, getpid());
|
||||
fflush(stdout);
|
||||
abort(); /* If gdb failed to start */
|
||||
} else {
|
||||
char buff;
|
||||
pDynString s = CreateDynString(100, 100);
|
||||
close(pipefd[1]);
|
||||
while (read(pipefd[0], &buff, 1) > 0) {
|
||||
DynStringConcatChar(s, buff);
|
||||
}
|
||||
SICSLogWrite(GetCharArray(s), eLogError);
|
||||
DeleteDynString(s);
|
||||
close(pipefd[0]);
|
||||
waitpid(child_pid, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void stack_trace(int mode) {
|
||||
switch (mode) {
|
||||
case 0:
|
||||
default:
|
||||
#ifdef SICS_HAS_BACKTRACE
|
||||
stack_trace_0();
|
||||
#endif
|
||||
break;
|
||||
case 1:
|
||||
#ifdef SICS_HAS_BFD
|
||||
stack_trace_bfd();
|
||||
#endif
|
||||
break;
|
||||
case 2:
|
||||
#ifdef SICS_HAS_GDB
|
||||
stack_trace_gdb();
|
||||
#endif
|
||||
break;
|
||||
case 3:
|
||||
#ifdef SICS_HAS_ABORT
|
||||
stack_trace_abort();
|
||||
#endif
|
||||
break;
|
||||
case 4:
|
||||
generate_stack_trace(0, 0);
|
||||
break;
|
||||
case 5:
|
||||
generate_stack_trace(0, 1);
|
||||
break;
|
||||
case 6:
|
||||
generate_stack_trace(1, 0);
|
||||
break;
|
||||
case 7:
|
||||
generate_stack_trace(1, 1);
|
||||
break;
|
||||
case 99:
|
||||
get_size_of_files("/tmp/core.*");
|
||||
break;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
/**
|
||||
* \brief Tests the stack_trace facility
|
||||
*/
|
||||
int Ansto_Stack_Trace(SConnection *pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) {
|
||||
int mode;
|
||||
void stack_trace(int mode);
|
||||
if (argc > 1)
|
||||
mode = atoi(argv[1]);
|
||||
else
|
||||
mode = 1;
|
||||
stack_trace(mode);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user