PSI UPDATE

r2720 | ffr | 2008-10-13 15:40:07 +1100 (Mon, 13 Oct 2008) | 2 lines
This commit is contained in:
Ferdi Franceschini
2008-10-13 15:40:07 +11:00
committed by Douglas Clowes
183 changed files with 20455 additions and 3661 deletions

View File

@ -1,5 +1,5 @@
#line 465 "histogram.w"
#line 467 "histogram.w"
/*---------------------------------------------------------------------------
H I S T D R I V
@ -72,7 +72,7 @@
void *pPriv;
} HistDriver;
#line 477 "histogram.w"
#line 479 "histogram.w"
#line 232 "histogram.w"
@ -81,8 +81,10 @@
void DeleteHistDriver(pHistDriver self);
int HistDriverConfig(pHistDriver self, pStringDict pOpt,
SConnection *pCon);
HistInt *DefaultSubSample(pHistDriver self, SConnection *pCon,
int bank, char *command);
#line 478 "histogram.w"
#line 480 "histogram.w"
#endif

View File

@ -1,5 +1,5 @@
#line 438 "histogram.w"
#line 440 "histogram.w"
/*--------------------------------------------------------------------------
H I S T M E M
@ -42,22 +42,22 @@
eReflect
} OverFlowMode;
#line 458 "histogram.w"
#line 460 "histogram.w"
/*--------------------------------------------------------------------------*/
#line 290 "histogram.w"
#line 292 "histogram.w"
pHistMem CreateHistMemory(char *drivername);
void DeleteHistMemory(void *self);
#line 306 "histogram.w"
#line 308 "histogram.w"
int HistGetOption(pHistMem self, char *name, char *result, int iResultLen);
int HistSetOption(pHistMem self, char *name, char *value);
int HistConfigure(pHistMem self, SConnection *pCon, SicsInterp *pSics);
#line 334 "histogram.w"
#line 336 "histogram.w"
float GetHistPreset(pHistMem self);
int SetHistPreset(pHistMem self, float fVal);
@ -73,7 +73,7 @@
void HistDirty(pHistMem self);
#line 364 "histogram.w"
#line 366 "histogram.w"
int SetHistogram(pHistMem self, SConnection *pCon,
int i,int iStart, int iEnd, HistInt *lData);
@ -85,7 +85,7 @@
HistInt *lData, int iDataLen);
int PresetHistogram(pHistMem self, SConnection *pCon, HistInt lVal);
#line 407 "histogram.w"
#line 409 "histogram.w"
int MakeHistMemory(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
@ -94,7 +94,7 @@
int argc, char *argv[]);
#line 460 "histogram.w"
#line 462 "histogram.w"
#endif

View File

@ -1,5 +1,5 @@
#line 483 "histogram.w"
#line 485 "histogram.w"
/*---------------------------------------------------------------------------
H I S T M E M -- Internal
@ -11,7 +11,7 @@
#ifndef SICSHISTMEMINT
#define SICSHISTMEMINT
#line 254 "histogram.w"
#line 256 "histogram.w"
typedef struct __HistMem {
pObjectDescriptor pDes;
@ -23,7 +23,7 @@
pICallBack pCall;
} HistMem;
#line 493 "histogram.w"
#line 495 "histogram.w"
#endif

70
README Normal file
View File

@ -0,0 +1,70 @@
SICS README
Requirements
- hdf-4, hdf5- libraries: http://hdf.ncsa.uiuc.edu
- szlib : same place as HDF
- Mini XML library : http://www.minixml.org/software.php
- libghttp :
http://ftp.gnome.org/pub/GNOME/source/libghttp/1.0/libghttp-1.0.9.tar.gz
- json-c : http://oss.metaparadigm.com/json-c
- tcl : any version from 8.0, package tcl-devel on most
modern linux distros
Building
Install the libraries stated above, preferably to a common place.
Then edit the suplied makefile, instance makefile_linux, and change:
- uncomment all the NI, NIOBJ, NILIB stuff, except if you want support
for the NI enet100 GPIB/TCP/IP converter.
- Edit linux_def and set HDFROOT to where you installed your libraries
- Review the CFLAGS and LIBS to match your setup. Consider file format
format support:
** HDF-4 required -DHDF4 in CFLAGS and -lmfdf -ldf in LIBS
** HDF-5 support requires: -DHDF5 in CFLAGS and -lhdf5 in LIBS
** XML support requires: -DNXXML -n CFLAGS and -lmxml in LIBS
- build with make -f makefile_linux
- Good Luck!!
Sorry, no configure script here. There are so few people building SICS
that it is not worth the effort. The effort really is to build the
libraries.
Running
In the sim directory there are startup scripts for a number of different
instruments. To run any of them:
- edit the instrument file and change the home or root variable at the
top to match your setup.
- run with: SICServer path-to-instrument-file
For example: SICServer sim/topsi/morpheus.tcl
- Common issues:
** tmp directory missing: create one
** SicsDataNumber file missing: create a file with a single 0 in it
Trying it out with telnet
- telnet host-where-sics-runs 2911
- type username and password: Spy 007 is a good idea for the supplied sims
- type SICS commands
Directories
sics : root directory containing the SICS kernel
sics/psi : psi specific drivers and stuff
sics/site_ansto : ANSTO specific stuff. Currently empty, ANSTO has its
own cvs
sics/dummy : example kit for defining an own site
sics/doc/user : user documentation
sics/doc/manager : manager documentation
sics/doc/programmer : programmer documentation
sics/matrix : matrix library used within SICS
sics/mcstas : code for virtual McStas instruments
sics/sim : control files for various instruments
sics/test : a sort of regression test for the SICS server

View File

@ -60,6 +60,7 @@
#include <string.h>
#include <tcl.h>
#include <time.h>
#include <limits.h>
#include "fortify.h"
#include "sics.h"
#include "splitter.h"
@ -478,6 +479,10 @@ extern char *SkipSpace(char *pPtr);
pCurrent = tail;
while(pCurrent)
{
/* the line below fixes problems with kill functions
* traversing the command list
*/
pCurrent->pNext = NULL;
if(pCurrent->KFunc)
{
pCurrent->KFunc(pCurrent->pData);
@ -487,6 +492,9 @@ extern char *SkipSpace(char *pPtr);
/* printf("Deleting %s\n",pCurrent->pName); */
free(pCurrent->pName);
}
if (pCurrent->stat) {
StatisticsKill(pCurrent->stat);
}
pTemp = pCurrent->pPrevious;
free(pCurrent);
pCurrent = pTemp;
@ -973,6 +981,11 @@ static void printType(SicsInterp *pSics, SConnection *pCon, char *typeName)
if(!pCom->pData)
return NULL;
if (cclass == NULL)
{
return pCom->pData;
}
pDum = (pDummy)pCom->pData;
if(strcmp(pDum->pDescriptor->name,cclass) == 0)
{
@ -980,6 +993,19 @@ static void printType(SicsInterp *pSics, SConnection *pCon, char *typeName)
}
return NULL;
}
/*---------------------------------------------------------------------------*/
pObjectDescriptor FindCommandDescriptor(SicsInterp *pSics, char *name)
{
CommandList *pCom;
pCom = FindCommand(pSics,name);
if(pCom == NULL || pCom->pData == NULL)
{
return NULL;
}
return ((pDummy)pCom->pData)->pDescriptor;
}
/*------------------------------------------------------------------------*/
void *FindDrivable(SicsInterp *pSics, char *name){
pIDrivable pDriv;
@ -1106,3 +1132,19 @@ char *FindAliases(SicsInterp *pSics, char *name)
DeleteDynString(result);
return charResult;
}
/*---------------------------------------------------------------------*/
void ForEachCommand(int (*scanFunction)(char *name, pDummy object, void *userData)
, void *userData)
{
CommandList *pCurrent;
for(pCurrent = pServ->pSics->pCList;
pCurrent != NULL;
pCurrent = pCurrent->pNext)
{
if(scanFunction(pCurrent->pName, pCurrent->pData, userData) == 0) {
return;
}
}
}

View File

@ -9,6 +9,7 @@
---------------------------------------------------------------------------*/
#ifndef SICSINTERPRETER
#define SICSINTERPRETER
#include "obdes.h"
#include "Scommon.h"
#include "statistics.h"
#include <tcl.h>
@ -142,19 +143,31 @@ typedef struct __SINTER
/*-------------------------------------------------------------------------
FindCommandData finds a command with the name given. It tests the name in the
ObjectDescriptor to be of name class. If all this succeeds a pointer
to the commands data structure is retuned. Else NULL
to the commands data structure is retuned. Else NULL.
Do not test the Object Descriptor name when comclass == NULL.
*/
void *FindCommandData(SicsInterp *pSics, char *name, char *comclass);
/*-------------------------------------------------------------------------
FindCommandDescriptor finds the descriptor of a command with the name given.
*/
pObjectDescriptor FindCommandDescriptor(SicsInterp *pSics, char *name);
/*------------------------------------------------------------------------
FindDrivable tries to find Drivable object by the name given. Returns a
pointer to the drivable interface in the case of success, NULL in
case of failure. In order to save me fixing header files the pointer must
be cast to the drivable interface pointer.
------------------------------------------------------------------------*/
*/
void *FindDrivable(SicsInterp *pics, char *name);
/*------------------------------------------------------------------------
Go through the command list and call scanFunction for every command
until the return value is 0.
*/
void ForEachCommand(int (*scanFunction)(char *name, pDummy object, void *userData)
, void *userData);
/*-----------------------------------------------------------------------
Get a copy of the Tcl interpreter
------------------------------------------------------------------------*/

View File

@ -22,6 +22,7 @@
#include <stdio.h>
#include <unistd.h>
#include "nserver.h"
#include "servlog.h"
/***************************** Necessary Globals ****************************/
@ -41,23 +42,22 @@
{
int iRet;
int debug = 0;
const char* filename = NULL;
char *file=NULL;
int i, firstArg=1;
/* initialise, will die on you if problems */
if(argc >= 2)
{
if (strcasecmp(argv[1], "-d") == 0)
{
if (strcasecmp(argv[1], "-d") == 0) {
debug = 1;
if (argc > 2)
filename = argv[2];
firstArg=2;
}
else
{
filename = argv[1];
for (i=firstArg; i<argc; i++) {
if (strcmp(argv[i], "-nolog") == 0) {
SICSLogEnable(0);
} else if (file == NULL) {
file = argv[i];
}
}
iRet = InitServer(filename, &pServ);
iRet = InitServer(file,&pServ);
if(!iRet)
{
printf("Unrecoverable error on server startup, exiting.........\n");

19
alias.c
View File

@ -212,3 +212,22 @@
}
return 1;
}
/*-------------------------------------------------------------------------------*/
int LocateAliasAction(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]){
char *aliases = NULL;
if(argc < 2){
SCWrite(pCon,"ERROR: missing argument aliasname for locating aliases",eError);
return 0;
}
strtolower(argv[1]);
aliases = FindAliases(pSics,argv[1]);
if(aliases == NULL){
SCWrite(pCon,"NONE", eValue);
} else {
SCPrintf(pCon,eValue,"%s = %s",argv[1], aliases);
}
return 1;
}

View File

@ -16,5 +16,7 @@
int argc, char *argv[]);
int MakeAlias(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int LocateAliasAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif

537
ascon.c Normal file
View File

@ -0,0 +1,537 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include "sics.h"
#include "splitter.h"
#include "ascon.i"
/*
CreateSocketAdress stolen from Tcl. Thanks to John Ousterhout
*/
static int CreateSocketAdress(
struct sockaddr_in *sockaddrPtr, /* Socket address */
char *host, /* Host. NULL implies INADDR_ANY */
int port) /* Port number */
{
struct hostent *hostent; /* Host database entry */
struct in_addr addr; /* For 64/32 bit madness */
(void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in));
sockaddrPtr->sin_family = AF_INET;
sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF));
if (host == NULL) {
addr.s_addr = INADDR_ANY;
} else {
hostent = gethostbyname(host);
if (hostent != NULL) {
memcpy((char *) &addr,
(char *) hostent->h_addr_list[0], (size_t) hostent->h_length);
} else {
addr.s_addr = inet_addr(host);
if (addr.s_addr == (unsigned long)-1) {
return 0; /* error */
}
}
}
/*
* There is a rumor that this assignment may require care on
* some 64 bit machines.
*/
sockaddrPtr->sin_addr.s_addr = addr.s_addr;
return 1;
}
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 micro)
*/
gettimeofday(&now, NULL);
return now.tv_sec + now.tv_usec / 1e6;
}
void AsconError(Ascon *a, char *msg, int errorno) {
static char *stateText[]={
"state 0", "kill", "state 2", "notConnected",
"connect", "start connect", "connect finished", "connect failed",
"write", "start write", "write finished", "write failed",
"read", "start read", "read finished", "read failed",
"state 16", "state 17", "state 18", "idle"
};
char *state;
if (a->state < 0 || a->state > 19) {
state = "bad state";
} else {
state = stateText[a->state];
}
if (errorno != 0) {
a->errList = ErrPutMsg(a->errList, "ASCERR: %s %s (during %s)", msg, strerror(errorno), state);
} else {
a->errList = ErrPutMsg(a->errList, "ASCERR: %s (during %s)", msg, state);
}
a->state |= AsconFailed;
}
static void AsconConnect(Ascon *a) {
/* input state: AsconConnectStart
output state: AsconFailed or AsconConnecting */
int ret;
struct sockaddr_in adr;
char *colon;
int port;
int oldopts;
if (a->fd < 0) {
a->fd = socket(AF_INET,SOCK_STREAM,0);
if (a->fd < 0) {
AsconError(a, "socket failed:", errno);
return;
}
}
colon = strchr(a->hostport, ':');
if (colon == NULL) return;
port = atoi(colon+1);
if (port <= 0) {
AsconError(a, "bad port number", 0);
return;
}
*colon = '\0';
ret = CreateSocketAdress(&adr, a->hostport, port);
*colon = ':';
if (ret == 0) {
AsconError(a, "bad host specification", 0);
return;
}
/* should we insert the workaround for lantronix server ? see network.c */
oldopts = fcntl(a->fd, F_GETFL, 0);
fcntl(a->fd, F_SETFL, oldopts | O_NONBLOCK);
ret = connect(a->fd, (struct sockaddr *)&adr, sizeof(struct sockaddr_in));
if (ret < 0) {
switch(errno) {
case EINPROGRESS:
case EALREADY:
case EISCONN:
a->state = AsconConnecting;
break;
default:
AsconError(a, "connect failed:", errno);
return;
}
}
a->state = AsconConnecting;
return;
}
int AsconStdInit(Ascon *a, SConnection *con,
int argc, char *argv[]) {
a->fd = -1;
a->state = AsconConnectStart;
a->reconnectInterval = 10;
a->hostport = strdup(argv[1]);
if(argc > 2){
a->sendTerminator = strdup(argv[2]);
} else {
a->sendTerminator = strdup("\n");
}
if(argc > 3){
a->timeout = atof(argv[3]);
} else {
a->timeout = 2.0; /* sec */
}
return 1;
}
int AsconReadGarbage(int fd) {
fd_set rmask;
struct timeval tmo = {0,0};
int l, ret, result;
char garbage[100];
FD_ZERO(&rmask);
result = 0;
do {
FD_SET(fd, &rmask);
ret = select(fd + 1, &rmask, NULL, NULL, &tmo);
if (ret > 0) {
l = recv(fd, garbage, sizeof garbage, 0);
if (l > 0) {
/* swallow */
result += l;
} else if (l == 0) {
errno = ECONNRESET;
return -2;
} else if (l < 0) {
return -2;
}
}
} while (ret > 0);
return result;
}
void PrintChar(char chr) {
if (chr <= 32 || chr >= 127) {
printf("%2.2x ", chr);
} else {
printf(" %c ", chr);
}
}
int AsconConnectSuccess(int fd) {
fd_set wmask, rmask;
struct timeval tmo = {0,0};
int oldopts;
int ret;
oldopts = fcntl(fd, F_GETFL, 0);
assert(oldopts | O_NONBLOCK); /* fd must be in non-blocking mode */
FD_ZERO(&wmask);
FD_ZERO(&rmask);
FD_SET(fd, &wmask);
FD_SET(fd, &rmask);
ret = select(fd + 1, &rmask, &wmask, NULL, &tmo);
if (ret > 0) {
assert(FD_ISSET(fd, &wmask));
if (FD_ISSET(fd, &rmask)) { /* there may already be data for read */
if (recv(fd, NULL, 0, 0) < 0) { /* zero length, check only return value */
ret = ASCON_RECV_ERROR; /* first recv failed */
}
} else {
if (send(fd, NULL, 0, 0) < 0) { /* zero length, check only return value */
ret = ASCON_SEND_ERROR; /* first send failed */
}
}
}
fcntl(fd, F_SETFL, oldopts & ~ O_NONBLOCK); /* reset to blocking mode */
return ret;
}
int AsconReadChar(int fd, char *chr) {
fd_set rmask;
struct timeval tmo = {0,0};
int ret;
FD_ZERO(&rmask);
FD_SET(fd, &rmask);
ret = select(fd + 1, &rmask, NULL, NULL, &tmo);
if (ret <= 0) return ret;
ret = recv(fd, chr, 1, 0);
/* PrintChar(*chr); */
fflush(stdout);
if (ret > 0) return 1;
if (ret == 0) {
errno = ECONNRESET;
return ASCON_DISCONNECTED;
}
return ASCON_RECV_ERROR;
}
int AsconWriteChars(int fd, char *data, int length) {
fd_set wmask;
struct timeval tmo = {0,0};
int ret;
if (length <= 0) return 0;
/*
{ int i;
for (i=0; i<length; i++) {
PrintChar(data[i]);
}
}
printf("<written\n");
*/
FD_ZERO(&wmask);
FD_SET(fd, &wmask);
ret = select(fd + 1, NULL, &wmask, NULL, &tmo);
if (ret <= 0) return ASCON_SELECT_ERROR;
ret = send(fd, data, length, 0);
if (ret > 0) return ret;
if (ret == 0) {
errno = ECONNRESET;
return ASCON_DISCONNECTED;
}
return ASCON_SEND_ERROR;
}
static double lastCall = 0;
int AsconStdHandler(Ascon *a) {
int ret;
int l;
char chr;
double now = DoubleTime();
if (now > lastCall + 0.5) { /* AsconStdHandler was not called since a long time (0.5 sec) */
if (lastCall != 0) { /* extend timeout time (for debugging purposes) */
a->start += now - lastCall - 0.5;
}
}
lastCall = now;
switch (a->state) {
case AsconConnectStart:
AsconConnect(a);
break;
case AsconConnecting:
ret = AsconConnectSuccess(a->fd);
if (ret == 0) {
/* in progress */
} else if (ret > 0) {
a->state = AsconConnectDone; /* success */
} else if (ret < 0) {
AsconError(a, "AsconConnectSuccess failed:", errno);
}
break;
case AsconWriteStart:
DynStringConcat(a->wrBuffer, a->sendTerminator);
a->wrPos = 0;
a->state = AsconWriting;
if(strstr(GetCharArray(a->wrBuffer),"@@NOSEND@@") != NULL){
a->state = AsconWriteDone;
}
break;
case AsconWriting:
AsconReadGarbage(a->fd);
l = GetDynStringLength(a->wrBuffer) - a->wrPos;
ret = AsconWriteChars(a->fd, GetCharArray(a->wrBuffer) + a->wrPos, l);
if (ret < 0) {
AsconError(a, "send failed:", errno);
/*
* Ooops: which state shall we go to after a write fail?
* This seems to retry.
*/
} else {
a->wrPos += ret;
if (a->wrPos >= GetDynStringLength(a->wrBuffer)) {
a->state = AsconWriteDone;
}
}
break;
case AsconReadStart:
DynStringClear(a->rdBuffer);
a->start = DoubleTime();
a->state = AsconReading;
break;
case AsconReading:
ret = AsconReadChar(a->fd, &chr);
while (ret > 0) {
a->start = DoubleTime();
if (chr == '\n') {
if (a->readState) {
/* swallow LF after CR */
DynStringClear(a->rdBuffer);
a->readState = 0;
} else {
DynStringConcatChar(a->rdBuffer, '\0');
a->state = AsconReadDone;
break;
}
} else if (chr == '\r') {
a->readState = 1;
DynStringConcatChar(a->rdBuffer, '\0');
a->state = AsconReadDone;
break;
} else {
if (DynStringConcatChar(a->rdBuffer, chr) == 0) {
AsconError(a, "DynStringConcatChar failed:", ENOMEM);
break;
}
a->readState = 0;
}
ret = AsconReadChar(a->fd, &chr);
}
if (ret < 0) {
AsconError(a, "AsconReadChar failed:", errno);
return 1;
}
if (a->state == AsconReadDone) {
DynStringConcatChar(a->rdBuffer, '\0');
} else {
if (a->timeout > 0) {
if (DoubleTime() - a->start > a->timeout) {
AsconError(a, "read timeout", 0);
a->state = AsconTimeout;
}
}
}
break;
default:
return 1;
}
return 1;
}
/* define type AsconProtocolList and functions AsconProtocolAdd etc. */
#define MC_NAME(T) AsconProtocol##T
#include "mclist.c"
static AsconProtocolList protocols={0};
void AsconInsertProtocol(AsconProtocol *protocol) {
AsconProtocolAdd(&protocols, protocol);
}
AsconHandler AsconSetHandler(Ascon *a, SConnection *con,
int argc, char *argv[]) {
AsconProtocol *p;
if (argc < 1) return NULL;
if (strcasecmp(argv[0], "std") == 0) {
if (argc < 2) return NULL;
AsconStdInit(a, con, argc, argv);
return AsconStdHandler;
}
for (p = protocols.head; p!= NULL; p=p->next) {
if (strcasecmp(p->name, argv[0]) == 0) {
if(p->init(a, con, argc, argv)){
return p->handler;
} else {
return NULL;
}
}
}
return NULL;
}
/* --- implementation of higher level interface ---- */
char *ConcatArgs(int argc, char *argv[]) {
return Arg2Tcl(argc, argv, NULL, -1);
}
Ascon *AsconMake(SConnection *con, int argc, char *argv[]) {
Ascon *a;
char *args;
a = calloc(1, sizeof(*a));
if (a == NULL) {
SCWrite(con, "ERROR: no memory", eError);
return NULL;
}
a->handler = AsconSetHandler(a, con, argc, argv);
if (a->handler == NULL) {
args = ConcatArgs(argc, argv);
if (!args) return NULL;
SCPrintf(con, eError, "ERROR: illegal protocol: %s", args);
free(args);
return NULL;
}
a->rdBuffer = CreateDynString(60, 63);
a->wrBuffer = CreateDynString(60, 63);
a->errList = NULL;
a->responseValid = 0;
a->reconnectInterval = 10;
a->lastReconnect = 0;
return a;
}
void AsconKill(Ascon *a) {
if (a->fd > 0) {
close(a->fd);
}
DeleteDynString(a->rdBuffer);
DeleteDynString(a->wrBuffer);
if (a->hostport) {
free(a->hostport);
}
if(a->sendTerminator){
free(a->sendTerminator);
}
if(a->private != NULL && a->killPrivate != NULL){
a->killPrivate(a->private);
}
free(a);
}
AsconStatus AsconTask(Ascon *a) {
double now;
while (a->handler(a)) {
switch (a->state) {
case AsconReading:
case AsconWriting:
return AsconPending;
case AsconNotConnected:
return AsconOffline;
break;
case AsconConnectDone:
a->state = AsconIdle;
return AsconReady;
case AsconWriteDone:
if (a->noResponse) {
return AsconReady;
}
a->state = AsconReadStart;
break;
case AsconReadDone:
a->state = AsconIdle;
a->responseValid = 1;
return AsconReady;
case AsconConnecting:
return AsconUnconnected;
default:
switch (a->state % 4) {
case AsconOnTheWay:
case AsconStart:
return AsconPending;
case AsconFailed:
if (a->state != AsconTimeout) {
now = DoubleTime();
if (now > a->lastReconnect + a->reconnectInterval) {
a->lastReconnect = now;
close(a->fd);
a->fd = -1;
a->state = AsconConnectStart;
}
}
return AsconFailure;
case AsconFinished:
if (a->state < AsconConnectFailed) {
return AsconUnconnected;
}
return AsconReady;
}
}
}
return AsconIdle;
}
int AsconWrite(Ascon *a, char *command, int noResponse) {
if (a->state <= AsconConnectFailed || a->state % 4 < AsconFinished) return 0;
DynStringCopy(a->wrBuffer, command);
a->noResponse = noResponse;
a->state = AsconWriteStart;
a->responseValid = 0;
AsconTask(a);
return 1;
}
char *AsconRead(Ascon *a) {
if (a->noResponse) {
a->noResponse=0;
return "";
}
if (a->state % 4 == AsconFailed) {
a->state = AsconIdle;
return "";
}
if (a->responseValid) {
a->responseValid = 0;
return GetCharArray(a->rdBuffer);
}
return NULL;
}
ErrMsg *AsconGetErrList(Ascon *a) {
return a->errList;
}

82
ascon.h Normal file
View File

@ -0,0 +1,82 @@
#ifndef ASCON_H
#define ASCON_H
#include "sics.h"
#include "errormsg.h"
/** \file
* \brief Asynchronous connection handling for devices controlled over tcp-ip
* connections. Interface for higher level modules.
*/
/** \brief the asynchronous connection
*/
typedef struct Ascon Ascon;
/** \brief the possible results of AsconTask
*/
typedef enum {
AsconOffline,
AsconUnconnected,
AsconPending,
AsconReady,
AsconFailure
} AsconStatus;
/** \brief make a new asynchronous connection
* \param con the SICS connection
* \param argc number of arguments
* \param argv the arguments. argv[0] must be the protocol name, the other arguments
* are protocol specific, but argv[1] is usually host::port
* \return the created connection or NULL on failure
*/
Ascon *AsconMake(SConnection *con, int argc, char *argv[]);
/** \brief kill function
* \param a the connection to be killed
*/
void AsconKill(Ascon *a);
/** \brief the task handler. To be called repeatedly.
* \param a the connection
* \return the state of the connection
*/
AsconStatus AsconTask(Ascon *a);
/** \brief write to the connection. allowed only when the state is AsconReady
* \param a the connection
* \param command the command to be sent
* \param noResponse 0 normally, 1 if no reponse is expected
* \return 1 on success, 0 when not ready
*/
int AsconWrite(Ascon *a, char *command, int noResponse);
/** \brief read from the connection. allowed only when a response is available
* \param a the connection
* \return the response when a response is ready
* NULL when the command has not completed and the response is not yet finished
* "" when the command has completed, but no response was expected.
* The result is only valid until the next call to other AsconXxx functions
* and has to be duplicated if needed later.
*/
char *AsconRead(Ascon *a);
/** \brief get the connections error list
* \return the error list
*/
ErrMsg *AsconGetErrList(Ascon *a);
/** \brief a helper function
* \param argc the number of args
* \param argv the args to be concatenated
* \result a allocated string containing the concatenated arguments
* the args are properly quoted to be used as tcl proc arguments
*/
char *ConcatArgs(int argc, char *argv[]);
/** \brief function for dealing with times with musec resolution
* \return absolute time as double value
*/
double DoubleTime(void);
#endif

156
ascon.i Normal file
View File

@ -0,0 +1,156 @@
#ifndef ASCON_I
#define ASCON_I
#include <sys/time.h>
#include "ascon.h"
#include "dynstring.h"
/** \file
* \brief Asynchronous connection handling for devices controlled over tcp-ip
* connections. Interface for the implementation of custom protocols.
*
* For the implementation of a custom protocol, you have to implement
* the handler function and the init function, declare the protocol
* of type AsconProtocol and call AsconInsertProtocol on startup.
* The handler and init functions are normally be a wrapper around AsconStdHandler
* and AsconStdInit
*
* The functions with fd as the first argument are utility functions with
* may be used in handler wrapper functions.
* On error, the return value may be one of the defined macros ASCON_xxx,
* and errno will give more details about the error.
*/
/**
* A sub-state of the connection. Only states with sub-state AsconStart may
* be set by the caller, and only when the sub-state is not AsconOnTheWay
*/
typedef enum { AsconOnTheWay=0, AsconStart=1, AsconFinished=2, AsconFailed=3 } AsconMode;
/**
* The state of the connection. The sub-state is state % 4.
*/
typedef enum {
AsconNotConnected=0+AsconFinished,
AsconConnecting=4+AsconOnTheWay,
AsconConnectStart=AsconConnecting+AsconStart,
AsconConnectDone=AsconConnecting+AsconFinished,
AsconConnectFailed=AsconConnecting+AsconFailed,
AsconWriting=8+AsconOnTheWay,
AsconWriteStart=AsconWriting+AsconStart,
AsconWriteDone=AsconWriting+AsconFinished,
AsconReading=12+AsconOnTheWay,
AsconReadStart=AsconReading+AsconStart,
AsconReadDone=AsconReading+AsconFinished,
AsconIdle=16+AsconFinished,
AsconTimeout=20 + AsconFailed
} AsconState;
/** \brief the task handler function prototype
*
* custom handlers must have this prototype
*/
typedef int (* AsconHandler)(Ascon *connection);
/** Ascon struct
* all members are public, allowing access by handler wrappers
*/
struct Ascon {
AsconState state; /**< the current state */
int fd; /**< socket */
int readState; /**< default implementation: 'was cr' */
pDynString rdBuffer;/**< read buffer */
pDynString wrBuffer;/**< write buffer */
int wrPos; /**< write buffer position */
double timeout; /**< read timeout (sec) */
char *sendTerminator; /**< terminator for sending messages */
char *hostport; /**< host:port to connect */
ErrMsg *errList; /**< error message list */
double start; /**< unix time when read was started */
void *private; /**< private data of protocol */
void (*killPrivate)(void *); /** < kill function for private */
int noResponse; /**< no response expected */
int responseValid; /**< a valid response is ready */
AsconHandler handler; /**< handler function */
double reconnectInterval; /**< reconnect interval */
double lastReconnect; /**< last connect try */
};
#define ASCON_SELECT_ERROR -1
#define ASCON_RECV_ERROR -2
#define ASCON_SEND_ERROR -3
#define ASCON_DISCONNECTED -4
/** \brief the standard handler routine.
* \param a the connection
* \return 0 when task has finished (connection to be closed), 1 when active
*
* In most cases a custom handler may be a wrapper around AsconStdHandler
*/
int AsconStdHandler(Ascon *a);
/** \brief initialize a standard connection
* \param a the connection
* \param con A connection to print errors too.
* \param hostport the tcp/ip address (syntax: host:port)
*
* In most cases a custom init function may be a wrapper around AsconStdInit
*/
int AsconStdInit(Ascon *a, SConnection *con, int argc, char *argv[]);
/** The Ascon Protocol
*/
typedef struct AsconProtocol {
struct AsconProtocol *next;
char *name;
AsconHandler handler;
int (*init)(Ascon *s, SConnection *con, int argc, char *argv[]);
} AsconProtocol;
/** \brief Insert a new protocol into the protocol list
* protocol the protocol (must be allocated by the caller, may be statically)
*/
void AsconInsertProtocol(AsconProtocol *protocol);
/** \brief close the connection and free internal used memory
* \param a the connection to be closed
* remark: the connection struct itself has to be freed manually
*/
void AsconClose(Ascon *a);
/** \brief swallow garbage (utility function)
* \param fd the socket
* \return >=0: number of chars swallowed, else error
*/
int AsconReadGarbage(int fd);
/** \brief check if a connection has succeded (utility function)
* \param fd the socket
* \return 1: connection succesful, 0: connection in progress, <0: error
*/
int AsconConnectSuccess(int fd);
/** \brief read one character, if available (utility function)
* \param fd the socket
* \param chr the result
* \return 1: succes, 0: no data available, <0: error
*/
int AsconReadChar(int fd, char *chr);
/** \brief non blocking write (utility function)
* \param fd the socket
* \param data the data (not nul-terminated, may contain nul)
* \param length the length of the data
* \return >0: number of written chars,0: write not yet possible, <0: error
*/
int AsconWriteChars(int fd, char *data, int length);
/** \brief store an error
* \param a The asynchronous I/O structure to store the
* error with
* \param msg The error message
* \param errorno The error number
*/
void AsconError(Ascon *a, char *msg, int errorno);
#endif

View File

@ -96,6 +96,9 @@ int defaultPrepareTxn(pAsyncProtocol p, pAsyncTxn txn, const char* cmd, int cmd_
}
txn->out_len = cmd_len;
txn->out_idx = 0;
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);

View File

@ -21,7 +21,8 @@ typedef enum {
ATX_NULL=0,
ATX_TIMEOUT=-1,
ATX_ACTIVE=1,
ATX_COMPLETE=2
ATX_COMPLETE=2,
ATX_DISCO=3
} ATX_STATUS;
struct __async_txn {

View File

@ -23,7 +23,6 @@
#include "nwatch.h"
#include <stdbool.h>
typedef struct __AsyncQueue AsyncQueue, *pAsyncQueue;
typedef struct __async_command AQ_Cmd, *pAQ_Cmd;
@ -361,7 +360,7 @@ static int MyCallback(void* context, int mode)
return 1;
}
int AsyncUnitEnqueHead(pAsyncUnit unit, pAsyncTxn context)
int AsyncUnitEnqueueHead(pAsyncUnit unit, pAsyncTxn context)
{
pAQ_Cmd myCmd = NULL;
@ -1074,6 +1073,18 @@ int AsyncUnitDestroy(pAsyncUnit unit)
return 1;
}
pAsyncUnit AsyncUnitFromQueue(pAsyncQueue queue){
pAsyncUnit result = NULL;
result = malloc(sizeof(AsyncUnit));
if(result == NULL){
return NULL;
}
memset(result,0,sizeof(AsyncUnit));
result->queue = queue;
return result;
}
void* AsyncUnitSetQueueContext(pAsyncUnit unit, void* cntx) {
void* hold;
assert(unit);

View File

@ -17,6 +17,9 @@
#define AQU_RETRY_CMD -4
#define AQU_POP_CMD -5
typedef struct __AsyncQueue AsyncQueue, *pAsyncQueue;
/** \brief create an AsyncUnit attached to a named AsyncQueue.
*
* \param queueName the name of the AsyncQueue to be used
@ -24,6 +27,11 @@
* \return positive if successful
*/
int AsyncUnitCreate(const char* queueName, pAsyncUnit* unit);
/** \brief Get an AsyncUnit from a given AsyncQueue
* \param queue The AsyncQueue for which this AsyncUnit is valid
* \return a new AsyncUnit or NULL on error
*/
pAsyncUnit AsyncUnitFromQueue(pAsyncQueue queue);
/** \brief create an AsyncUnit attached to an anonymous AsyncQueue.
*

View File

@ -11,6 +11,11 @@
Added a tail facility
Mark Koennecke, October 1999
Added compact mode:
- timestamps look different and are omitted if no other text is written
- socket number information is written on the timestamp line
--------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
@ -34,50 +39,30 @@
/*-------------------- the tail buffer ---------------------------------*/
static pCircular pTail = NULL;
#define MAXTAIL 1000
/*----------------------------------------------------------------------*/
#define NOID -1964
static time_t lastStamp = 0;
static time_t iCompact = 0;
static time_t tLastWrite = 0;
char *cmdPrompt=">";
static int lastId=NOID;
static time_t tLogfile = 0;
static time_t tStamp = 0;
static int iEnd = 1;
static int iAutoActive = 0;
static int iIntervall = 60;
/*----------------------------------------------------------------------*/
void WriteToCommandLog(char *prompt,char *text)
void WriteToCommandLogId(char *prompt, int id, char *text)
{
int iNL = 0, iPos;
char *pPtr = NULL, *pCopy = NULL, *pText = NULL;
char myBuffer[1024];
int l, iPos;
char *pPtr = NULL, *pCopy = NULL, *strippedText = text;
struct tm *nowTm;
time_t now;
char stamp1[32], stamp2[32], buffer[80];
int doStamp, doStampId;
/*
we change the text, so we need to make a local copy. A copy
is dynamically allocated only if it does not fit into
myBuffer.
*/
if(strlen(text) > 1023){
pCopy = (char *)malloc((strlen(text)+2)*sizeof(char));
if(pCopy == NULL){
return;
}
memset(pCopy,0,(strlen(text)+2)*sizeof(char));
strcpy(pCopy,text);
pText = pCopy;
} else {
strcpy(myBuffer,text);
pText = myBuffer;
}
/* figure out if we have to do a newline with pText as well */
pPtr = strrchr(pText,'\n');
if(pPtr != NULL)
{
iPos = pPtr - pText;
if(iPos >= (strlen(pText) - 2) )
{
iNL = 1;
}
}
/* supress status messages */
if(strstr(pText,"status =") != NULL)
{
if(pCopy != NULL){
free(pCopy);
}
/* suppress status messages */
if (strstr(text,"status =") != NULL) {
return;
}
@ -85,67 +70,139 @@
commandlog work and TRANSACTIONSTART in order to make the logfiles
shorter
*/
if(strstr(pText,"TRANSACTIONFINISHED") != NULL ||
strstr(pText,"TRANSACTIONSTART") != NULL)
{
if(pCopy != NULL){
free(pCopy);
if (strstr(text,"TRANSACTIONSTART") != NULL) {
return;
}
if (strstr(text,"TRANSACTIONFINISHED") != NULL) {
return;
}
/* we make a local copy, stripping off the newline at the
end. We anyway need a copy later for the circular buffer */
l = strlen(text);
pPtr = strrchr(text,'\n');
if (pPtr != NULL && (pPtr[1]=='\0' || pPtr[2] == '\0')) {
l = pPtr - text;
}
pCopy = malloc(l+1);
if (pCopy == NULL) return;
strncpy(pCopy, text, l);
pCopy[l]='\0';
if (prompt == cmdPrompt && iCompact) {
pPtr = strstr(pCopy, "fulltransact ");
if (pPtr && pPtr < pCopy+3) {
strippedText = pPtr + 13;
}
pPtr = strstr(pCopy, "transact ");
if (pPtr && pPtr < pCopy+3) {
strippedText = pPtr + 9;
}
}
/* create tail buffer as needed */
if(!pTail)
{
if (!pTail) {
pTail = createCircular(MAXTAIL,free);
}
now = time(NULL);
doStamp = 0;
doStampId = 0;
if (id == NOID) {
if (!prompt) {
prompt="";
} else {
snprintf(buffer, sizeof buffer, "%s ", prompt);
prompt = buffer;
}
} else if (iCompact == 0) {
if (!prompt) {
snprintf(buffer, sizeof buffer, "To sock %d : ", id);
} else {
snprintf(buffer, sizeof buffer, "sock %d>%s ", id, prompt);
}
prompt = buffer;
} else {
if (id != lastId) {
lastId = id;
doStampId = 1;
}
if (!prompt) {
prompt="";
} else {
snprintf(buffer, sizeof buffer, "%s ", prompt);
prompt = buffer;
}
}
if (iCompact > 0) { /* write time stamp */
if (now/iCompact != lastStamp/iCompact) {
doStamp = 1;
doStampId = 1;
}
if (doStampId) {
lastStamp = now;
nowTm = localtime(&now);
strftime(stamp1, sizeof stamp1, "=== %H:%M:%S ===", nowTm);
if (id != NOID) {
snprintf(stamp2, sizeof stamp2, " socket %d ===", id);
} else {
stamp2[0] = '\0';
}
}
}
/* user file */
if(fd != NULL)
{
if(iNL)
{
fprintf(fd,"%s %s",prompt, pText);
}
else
{
fprintf(fd,"%s %s\n",prompt, pText);
if (fd != NULL) {
if (doStampId) {
fprintf(fd,"%s %s\n", stamp1, stamp2);
}
fprintf(fd,"%s%s\n", prompt, pCopy);
}
/* automatic file */
if(fauto != NULL)
{
time(&tLastWrite);
if(iNL)
{
fprintf(fauto,"%s %s",prompt, pText);
}
else
{
fprintf(fauto,"%s %s\n",prompt, pText);
if (fauto != NULL) {
tLastWrite = now;
if (doStampId) {
fprintf(fauto,"%s%s\n", stamp1, stamp2);
}
fprintf(fauto,"%s%s\n", prompt, strippedText);
}
/* to all listening sockets. The check is necessary to resolve a shutdown problem */
if(pServ->pTasker != NULL)
{
TaskSignal(pServ->pTasker,COMLOG,pText);
if (pServ->pTasker != NULL) {
if (doStamp) {
TaskSignal(pServ->pTasker,COMLOG,stamp1);
}
TaskSignal(pServ->pTasker,COMLOG,pCopy);
}
/* tail buffer */
if(pTail != NULL)
{
if(iNL)
{
pPtr = strrchr(pText,'\n');
*pPtr = ' ';
}
setCircular(pTail,strdup(pText));
if (pTail != NULL) {
if (doStamp) {
setCircular(pTail,strdup(stamp1));
nextCircular(pTail);
}
if(pCopy != NULL){
free(pCopy);
setCircular(pTail,pCopy);
nextCircular(pTail);
}
lastId = id;
}
/*------------------------------------------------------------------------*/
void WriteToCommandLog(char *prompt, char *text)
{
WriteToCommandLogId(prompt, NOID, text);
}
/*------------------------------------------------------------------------*/
void WriteToCommandLogCmd(int id, char *text)
{
WriteToCommandLogId(cmdPrompt, id, text);
}
/*------------------------------------------------------------------------*/
int CompactCommandLog(void) {
return iCompact > 0;
}
/*------------------------------------------------------------------------*/
static void PrintTail(int iNum, SConnection *pCon)
@ -233,9 +290,9 @@
pInst = FindVariable(pServ->pSics,"instrument");
if(pInst)
{
sprintf(pBueffel,"Logfile started at instument %s at %s",
sprintf(pBueffel,"Logfile started at instrument %s at %s",
pInst->text,pTime);
WriteToCommandLog("SYS>> ", pBueffel);
WriteToCommandLog("SYS>>", pBueffel);
}
/* if a file to execute is configured, execute it */
@ -259,12 +316,6 @@
AutoTask puts a time stamp into the auto log file any hour and
creates a new log file any 24 hours
*/
static time_t tLogfile = 0;
static time_t tStamp = 0;
static int iEnd = 1;
static int iAutoActive = 0;
static int iIntervall = 60;
static int AutoTask(void *pData)
{
time_t tNow;
@ -296,7 +347,7 @@
if(tLogfile < 0)
tLogfile = tNow + 60*60*24;
}
if(tNow > tStamp)
if(tNow > tStamp && iIntervall > 0)
{
CLFormatTime(pTime,79);
WriteToCommandLog("TIMESTAMP>> ",pTime);
@ -319,11 +370,10 @@
fflush(fauto);
}
if (fauto && tLastWrite != 0 && tNow > tLastWrite) {
if (fauto && tLastWrite > 0 && tNow > tLastWrite) {
fflush(fauto);
tLastWrite = 0;
}
return iEnd;
}
/*----------- a command to configure the log --------------------------*/
@ -450,15 +500,19 @@
return 0;
}
iIntervall = iVal;
SCSendOK(pCon);
}
SCPrintf(pCon,eValue,"%s.intervall [min] = %d", argv[0], iIntervall);
return 1;
}
else
else if(strcmp(argv[1],"compact") == 0)
{
sprintf(pBueffel,"autolog.intervall = %d", iIntervall);
SCWrite(pCon,pBueffel,eValue);
return 1;
if(argc > 2)
{
iCompact = atoi(argv[2]);
if (iCompact > 0) iIntervall = 0;
}
SCPrintf(pCon,eValue,"%s.compact [sec] = %d", argv[0], iCompact);
return 1;
}
else if(strcmp(argv[1],"close") == 0) /* close command */
{

View File

@ -10,6 +10,9 @@
#ifndef COMMANDLOG
#define COMMANDLOG
void WriteToCommandLog(char *prompt,char *pText);
void WriteToCommandLogId(char *prompt, int id, char *text);
void WriteToCommandLogCmd(int id, char *text);
int CompactCommandLog(void);
int CommandLog(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);

View File

@ -335,6 +335,7 @@ static float invokeReadScript(pConfigurableVirtualMotor self,
if(status != TCL_OK){
snprintf(self->scriptError,510,"ERROR: Tcl subsystem reported %s",
Tcl_GetStringResult(pTcl));
SCWrite(pCon,self->scriptError,eError);
}
return atof(Tcl_GetStringResult(pTcl));
}

316
conman.c
View File

@ -67,8 +67,9 @@
#include "uubuffer.h"
#include "commandlog.h"
#include "stptok.h"
#include "statusfile.h"
#include "sicshipadaba.h"
#include "protocol.h"
/*
#define UUDEB 1
define UUDEB , for buffer writing for checking encoding */
@ -79,7 +80,7 @@ extern pServer pServ;
/*------ Max Size of Command Stack */
#define MAXSTACK 100
#define MAXSTACK 1024
/*---------- Magic ID Header */
#define CONMAGIC 26051958
/*-------------------------------------------------------------------------
@ -96,6 +97,14 @@ extern pServer pServ;
static long lastIdent = 0;
/*------------- sending connection (prevent double write when listening) ----*/
static SConnection *sendingConnection = NULL;
/*------------- storing connection and context for later use ----*/
struct SCStore {
SConnection *pCon;
long ident;
int inMacro;
long macroStack;
commandContext cc;
};
/*===========================================================================*/
static char *ConName(long ident) {
static char name[32];
@ -357,6 +366,7 @@ extern pServer pServ;
}
assert( (iMode == 0) || (iMode == 1));
self->iMacro = iMode;
/* SCPrintf(self,eError, "SCsetMacro = %lx, %d\n", (long int)self, iMode); */
return 1;
}
/*---------------------------------------------------------------------------*/
@ -383,7 +393,7 @@ extern pServer pServ;
free(pVictim->pSock);
pVictim->pSock = NULL;
}
WriteToCommandLog("SYS> ",
WriteToCommandLog("SYS>",
"ERROR: Erraneous deletion of used Connection stopped");
return;
}
@ -400,7 +410,7 @@ extern pServer pServ;
root = GetHipadabaRoot();
if(root != NULL)
{
InternalRemoveHipadabaCallback(root,pVictim->ident);
RemoveConnectionCallbacks(root,pVictim);
}
/*
@ -416,7 +426,8 @@ extern pServer pServ;
}
/* log the kill */
if(pVictim->pSock && pVictim->iLogin == 1)
if(pVictim->pSock && pVictim->iLogin == 1 &&
(pVictim->iUserRights < 3 || !CompactCommandLog()) )
{
sprintf(pBueffel,"Deleting connection %d",pVictim->pSock->sockid);
WriteToCommandLog("SYS>",pBueffel);
@ -640,8 +651,10 @@ static int doSockWrite(SConnection *self, char *buffer)
if(!iRet)
{
SCnoSock(self);
if(!self->listening && self->iLogin == 1){
WriteToCommandLog("SYS> ","Connection broken on send");
if(!self->listening && self->iLogin == 1 &&
(self->iUserRights < 3 || !CompactCommandLog()) )
{
WriteToCommandLog("SYS>","Connection broken on send");
}
}
}
@ -683,7 +696,7 @@ static void writeToLogFiles(SConnection *self, char *buffer)
return 0;
}
if (buffer[0] == '\0' && iOut == eFinish) {
if (buffer[0] == '\0' && iOut >= eStart && iOut <= eEvent) {
return 1; /* do not write empty line */
}
@ -712,18 +725,16 @@ static void writeToLogFiles(SConnection *self, char *buffer)
{
if(self->iMacro != 1)
{
sprintf(pBueffel,"To sock %d :",iRet);
sendingConnection = self;
WriteToCommandLog(pBueffel,buffer);
WriteToCommandLogId(NULL,iRet,buffer);
sendingConnection = NULL;
}
else
{
if(iOut == eError || iOut == eWarning)
{
sprintf(pBueffel,"To sock %d :",iRet);
sendingConnection = self;
WriteToCommandLog(pBueffel,buffer);
WriteToCommandLogId(NULL,iRet,buffer);
sendingConnection = NULL;
}
}
@ -752,6 +763,92 @@ static void writeToLogFiles(SConnection *self, char *buffer)
}
return 1;
}
/*--------------------------------------------------------------------------*/
int SCACTWrite(SConnection *self, char *buffer, int iOut)
{
int i, iPtr, iRet;
char pBueffel[1024];
char *pPtr = pBueffel;
commandContext cx;
if(!VerifyConnection(self))
{
return 0;
}
if (buffer[0] == '\0' && iOut >= eStart && iOut <= eEvent) {
return 1; /* do not write empty line */
}
/* log it for any case */
if(self->pSock)
{
iRet = self->pSock->sockid;
}
else
{
iRet = 0;
}
sprintf(pBueffel,"Next line intended for socket: %d",iRet);
SICSLogWrite(pBueffel,eInternal);
SICSLogWrite(buffer,iOut);
/* write to commandlog if user or manager privilege */
if(SCGetRights(self) <= usUser)
{
if(self->iMacro != 1)
{
sendingConnection = self;
WriteToCommandLogId(NULL,iRet,buffer);
sendingConnection = NULL;
}
else
{
if(iOut == eError || iOut == eWarning)
{
sendingConnection = self;
WriteToCommandLogId(NULL,iRet,buffer);
sendingConnection = NULL;
}
}
}
/*
* copy in ACT
*/
if(strlen(buffer) + 30 > 1024){
pPtr = (char *)malloc((strlen(buffer)+30)*sizeof(char));
memset(pPtr,0,strlen(buffer)+20);
}
cx = SCGetContext(self);
sprintf(pPtr,"%d::>%s<::", cx.transID, buffer);
/* put it into the interpreter if present */
if(SCinMacro(self))
{
InterpWrite(pServ->pSics,buffer);
/* print it to client if error message */
if((iOut== eError) || (iOut == eWarning) )
{
iRet = doSockWrite(self,pPtr);
}
}
else /* not in interpreter, normal logic */
{
/* is this really to be printed ? */
if(iOut < self->iOutput)
return 0;
/* first the socket */
iRet = doSockWrite(self,pPtr);
writeToLogFiles(self,buffer);
}
if(pPtr != pBueffel){
free(pPtr);
}
return 1;
}
/*--------------------------------------------------------------------------*/
int SCWriteWithOutcode(SConnection *self, char *buffer, int iOut)
{
@ -764,7 +861,7 @@ static void writeToLogFiles(SConnection *self, char *buffer)
return 0;
}
if (buffer[0] == '\0' && iOut == eFinish) {
if (buffer[0] == '\0' && iOut >= eStart && iOut <= eEvent) {
return 1; /* do not write empty line */
}
@ -784,9 +881,8 @@ static void writeToLogFiles(SConnection *self, char *buffer)
/* write to commandlog if user or manager privilege */
if(SCGetRights(self) <= usUser && self->iMacro != 1)
{
sprintf(pBueffel,"To sock %d :",iRet);
sendingConnection = self;
WriteToCommandLog(pBueffel,buffer);
WriteToCommandLogId(NULL,iRet,buffer);
sendingConnection = NULL;
}
@ -952,6 +1048,11 @@ pDynString SCEndBuffering(SConnection *pCon)
SICSLogWrite(pBueffel,eInternal);
SICSLogWrite(buffer,iOut);
/* put it into the interpreter if present */
if(SCinMacro(self))
{
InterpWrite(pServ->pSics,buffer);
}
return 1;
}
/*--------------------------------------------------------------------------
@ -968,16 +1069,40 @@ pDynString SCEndBuffering(SConnection *pCon)
return 0;
}
/* log it for any case */
if(self->pSock)
{
iRet = self->pSock->sockid;
}
else
{
iRet = -10;
}
/* put into Serverlog */
sprintf(pBueffel,"Next line intended for socket(5): %d",-10);
sprintf(pBueffel,"Next line intended for socket: %d",iRet);
SICSLogWrite(pBueffel,eInternal);
SICSLogWrite(buffer,iOut);
/* write to commandlog if user or manager privilege */
if(SCGetRights(self) <= usUser && self->iMacro != 1)
if(SCGetRights(self) <= usUser)
{
sprintf(pBueffel,"To sock %d :",-10);
WriteToCommandLog(pBueffel,buffer);
if(self->iMacro != 1)
{
sendingConnection = self;
WriteToCommandLogId(NULL,iRet,buffer);
sendingConnection = NULL;
}
else
{
if(iOut == eError || iOut == eWarning)
{
sendingConnection = self;
WriteToCommandLogId(NULL,iRet,buffer);
sendingConnection = NULL;
}
}
}
/* put it into the interpreter if present */
@ -1047,8 +1172,9 @@ pDynString SCEndBuffering(SConnection *pCon)
int SCWriteZipped(SConnection *self, char *pName, void *pData, int iDataLen)
{
char outBuf[65546], *pBuf = NULL, noutBuf[ZIPBUF], *pHeader = NULL;
int compressedLength, iRet, iRet2, iCount;
int compressedLength, iRet, iRet2, iCount, protocolID;
z_stream compStream;
commandContext cc;
/* check for a valid connection */
if(!VerifyConnection(self))
@ -1123,7 +1249,15 @@ pDynString SCEndBuffering(SConnection *pCon)
/* write header line */
memset(outBuf,0,65536);
sprintf(outBuf,"SICSBIN ZIP %s %d\r\n",pName,compressedLength);
protocolID = GetProtocolID(self);
if(protocolID == 5){
cc = SCGetContext(self);
sprintf(outBuf,"SICSBIN ZIP %s %d %d\r\n",pName,
compressedLength, cc.transID);
} else {
sprintf(outBuf,"SICSBIN ZIP %s %d \r\n",pName,compressedLength);
}
pHeader = strdup(outBuf);
if(pHeader == NULL)
{
@ -1348,8 +1482,7 @@ pDynString SCEndBuffering(SConnection *pCon)
SetStatus(eOld);
CostaLock(pCon->pStack);
strncpy(pResult,pPtr,iLen);
sprintf(pFrom,"Prompted from sock %2.2d: ", pCon->pSock->sockid);
WriteToCommandLog(pFrom,pPtr);
WriteToCommandLogId(" prompted>", pCon->pSock->sockid, pPtr);
return 1;
}
}
@ -1449,14 +1582,6 @@ pDynString SCEndBuffering(SConnection *pCon)
/* print to command log if user or manager */
if(SCGetRights(self) <= usUser)
{
if(self->pSock != NULL)
{
sprintf(pBueffel,"sock %d>>",self->pSock->sockid);
}
else
{
strcat(pBueffel,"CONT or CRON>> ");
}
/*
* This is a fix to suppress cron messages in the success
* case
@ -1464,7 +1589,12 @@ pDynString SCEndBuffering(SConnection *pCon)
if(SCGetWriteFunc(self) != SCNotWrite)
{
sendingConnection = self;
WriteToCommandLog(pBueffel,pCommand);
if(self->pSock != NULL)
{
WriteToCommandLogCmd(self->pSock->sockid, pCommand);
} else {
WriteToCommandLog("CRON>>",pCommand);
}
sendingConnection = NULL;
}
}
@ -1472,7 +1602,6 @@ pDynString SCEndBuffering(SConnection *pCon)
/* invoke */
self->inUse++;
self->eInterrupt = eContinue;
self->parameterChange = 0;
/*
get first word of command
*/
@ -1481,18 +1610,8 @@ pDynString SCEndBuffering(SConnection *pCon)
SCAdvanceContext(self,pBueffel);
iRet = InterpExecute(pInter,self,pCommand);
SCPopContext(self);
if(self->parameterChange == 1)
{
/*
automatically save changed parameters
*/
pFile = IFindOption(pSICSOptions,"statusfile");
if(pFile != NULL)
{
WriteSicsStatus(pInter,pFile,0);
self->parameterChange = 0;
}
}
StatusFileTask(NULL); /* save changed parameters */
self->inUse--;
return iRet;
}
@ -1501,7 +1620,7 @@ pDynString SCEndBuffering(SConnection *pCon)
config OutCode val sets an new output code
config Rights User Password sets and verifies new user rights
config File Filename Logs to another file
config output normal | withcode Sets output mode
config output normal | withcode | ACT Sets output mode
config listen 0 | 1 enables commandlog listen mode
---------------------------------------------------------------------------*/
@ -1509,6 +1628,7 @@ pDynString SCEndBuffering(SConnection *pCon)
int argc, char *argv[])
{
char pBueffel[512];
char pHost[132];
int i, iRet;
int iNum;
@ -1640,6 +1760,10 @@ pDynString SCEndBuffering(SConnection *pCon)
{
SCSetWriteFunc(pCon,SCWriteWithOutcode);
}
else if(strcmp(argv[2],"act") == 0)
{
SCSetWriteFunc(pCon,SCACTWrite);
}
else
{
SCWrite(pCon,"ERROT: output mode not recognised",eError);
@ -1664,10 +1788,19 @@ pDynString SCEndBuffering(SConnection *pCon)
SCWrite(pCon,pBueffel,eError);
return 0;
}
pCon->iUserRights = i;
if (CompactCommandLog()) {
if (pCon->iUserRights < 3 || i < 3) {
NETInfo(pCon->pSock,pHost,sizeof pHost);
sprintf(pBueffel,"User %s from %s switched to %d privilege",
argv[2],pHost,i);
WriteToCommandLogId("SYS>",pCon->pSock->sockid,pBueffel);
}
} else {
sprintf(pBueffel,"User %s socket %d switched to %d privilege",
argv[2],pCon->pSock->sockid,i);
WriteToCommandLog("SYS>",pBueffel);
}
pCon->iUserRights = i;
SCWrite(pCon,"Change of Authorisation Acknowledged",eWarning);
return 1;
}
@ -1920,6 +2053,11 @@ pDynString SCEndBuffering(SConnection *pCon)
{
return 0;
}
if(self->pSock->iType == 0)
{
NetReadRemove(pServ->pReader,self->pSock);
self->iEnd = 1;
}
if(self->iEnd)
{
@ -1987,11 +2125,21 @@ pDynString SCEndBuffering(SConnection *pCon)
self->iLogin = 1;
SCSetRights(self,iRet);
pHost[0] = '\0';
if (CompactCommandLog()) {
if (iRet < 3) {
NETInfo(self->pSock,pHost,131);
sprintf(pBueffel,"Accepted connection %s from %s as %s",
ConName(self->ident), pHost, pUser);
SICSLogWrite(pBueffel,eInternal);
WriteToCommandLogId("SYS>", self->pSock->sockid, pBueffel);
}
} else {
NETInfo(self->pSock,pHost,131);
sprintf(pBueffel,"Accepted connection %s on socket %d from %s",
ConName(self->ident), self->pSock->sockid, pHost);
SICSLogWrite(pBueffel,eInternal);
WriteToCommandLog("SYS >", pBueffel);
}
free(pPtr);
return 1;
}
@ -2070,11 +2218,7 @@ pDynString SCEndBuffering(SConnection *pCon)
/*-----------------------------------------------------------------------*/
void SCparChange(SConnection *self)
{
if(!VerifyConnection(self))
{
return;
}
self->parameterChange = 1;
StatusFileDirty();
}
/*------------------------------------------------------------------------*/
int SCActive(SConnection *self)
@ -2093,24 +2237,74 @@ int SCActive(SConnection *self)
return 0;
}
/*--------------------------------------------------------------------------*/
void SCSave(SCStore *con, SConnection *pCon) {
con->pCon = pCon;
if (pCon) {
con->ident = pCon->ident;
SCStore *SCSave(SConnection *pCon, SCStore *oldStore) {
commandContext cc;
if (oldStore == NULL) {
oldStore = calloc(1,sizeof(*oldStore));
assert(oldStore);
}
oldStore->pCon = pCon;
if (pCon) {
oldStore->ident = pCon->ident;
oldStore->inMacro = pCon->iMacro;
oldStore->cc = SCGetContext(pCon);
oldStore->macroStack = 0;
}
return oldStore;
}
/*--------------------------------------------------------------------------*/
SConnection *SCLoad(SCStore *con) {
SConnection *pCon;
SConnection *SCLoad(SCStore *conStore) {
SConnection *pCon = NULL;
commandContext old;
pCon = con->pCon;
if (conStore) {
pCon = conStore->pCon;
}
if (pCon) {
if (con->ident != pCon->ident) {
con->pCon = NULL; /* connection is dead */
if (conStore->ident != pCon->ident) {
conStore->pCon = NULL; /* connection is dead */
pCon = NULL;
}
}
if (pCon) {
return pCon;
}
return pServ->dummyCon;
}
/*--------------------------------------------------------------------------*/
SConnection *SCStorePush(SCStore *conStore) {
SConnection *pCon;
pCon = SCLoad(conStore);
/* push macro flag on stack */
conStore->macroStack <<= 1;
conStore->macroStack |= (pCon->iMacro != 0);
SCsetMacro(pCon, conStore->inMacro);
SCPushContext2(pCon, conStore->cc);
return pCon;
}
/*--------------------------------------------------------------------------*/
void SCStorePop(SCStore *conStore) {
SConnection *pCon;
pCon = SCLoad(conStore);
SCPopContext(pCon);
/* pop macro flag from stack
SCsetMacro(pCon,conStore->macroStack);
*/
SCsetMacro(pCon, (conStore->macroStack & 1));
conStore->macroStack >>= 1;
}
/*--------------------------------------------------------------------------*/
int SCStoreConnected(SCStore *conStore) {
return (conStore &&
conStore->pCon &&
conStore->pCon->ident == conStore->ident);
}
/*--------------------------------------------------------------------------*/
void SCStoreFree(SCStore *conStore) {
free(conStore);
}
/* --------------------------------------------------------------------------*/
long SCTagContext(SConnection *self, char *tagName)

View File

@ -58,7 +58,6 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
int iUserRights;
int inUse;
int iGrab; /* grab flag for token*/
int parameterChange;
int sicsError;
/*
@ -123,6 +122,7 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
int SCNotWrite(SConnection *self, char *buffer, int iOut);
int SCNormalWrite(SConnection *self, char *buffer, int iOut);
int SCWriteWithOutcode(SConnection *self, char *buffer, int iOut);
int SCACTWrite(SConnection *self, char *buffer, int iOut);
/*********************** I/O Buffering ***********************************/
int SCStartBuffering(SConnection *pCon);
pDynString SCEndBuffering(SConnection *pCon);
@ -168,16 +168,25 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
int ConSicsAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/******************************** Store ************************************/
typedef struct {
SConnection *pCon;
long ident;
} SCStore;
typedef struct SCStore SCStore;
void SCSave(SCStore *con, SConnection *pCon);
/* save a connection for later use. */
SCStore *SCSave(SConnection *pCon, SCStore *oldStore);
/* save a connection and its context for later use. */
SConnection *SCLoad(SCStore *con);
/* check con and return SConnection if still valid or NULL otherwise. */
SConnection *SCLoad(SCStore *conStore);
/* check con and return SConnection if still valid or a dummy connection otherwise. */
SConnection *SCStorePush(SCStore *conStore);
/* load connection and push stored context. Must be paired with an SCStorePop command */
void SCStorePop(SCStore *conStore);
/* pop context */
int SCStoreConnected(SCStore *conStore);
/* check if a stored connection is not closed */
void SCStoreFree(SCStore *conStore);
/* free an SCStore */
void KillFreeConnections(void);

5
danu.c
View File

@ -363,8 +363,9 @@ int NewThousand(pDataNumber self)
if(SCMatchRights(pCon,usMugger))
{
DecrementDataNumber(self);
SCWrite(pCon,"Data file killed",eWarning);
iNum = DecrementDataNumber(self);
snprintf(pBueffel,511,"Data file %d killed", iNum+1);
SCWrite(pCon,pBueffel,eWarning);
return 1;
}
else

View File

@ -103,7 +103,7 @@ void DevexecLog(char *operation, char *device) {
if(devLog != NULL){
gettimeofday(&tv,&tm);
fprintf(devLog, "DEVEXEC:%s:%s:%ld:%ld\n",operation,device,
tv.tv_sec, tv.tv_usec);
(long)tv.tv_sec, (long)tv.tv_usec);
fflush(devLog);
}
}
@ -170,6 +170,7 @@ typedef struct {
pICallBack pCall;
time_t lastRun;
int paused;
int taskRunning;
} ExeList;
static pExeList pExecutor = NULL;
@ -220,6 +221,7 @@ typedef struct {
pRes->iLock = 0;
pRes->drivePrint = 0;
pRes->paused = 0;
pRes->taskRunning = 0;
pRes->pCall = CreateCallBackInterface();
pRes->lastRun = time(NULL);
pRes->pDes->GetInterface = DevexecInterface;
@ -650,7 +652,7 @@ static int checkInterrupt(pCheckContext pCheck, int targetStatus){
}
/*--------------------------------------------------------------------------*/
static int initializeCheck(pCheckContext pCheck, pDevEntry pDev){
int eCode;
int eCode = HWFault;
SCPushContext(pCheck->self->pOwner,
pDev->comCon.transID, pDev->comCon.deviceID);
@ -1364,8 +1366,20 @@ static int testFinish(pExeList self){
return 0;
}
self->lastRun = time(NULL);
if(self->taskRunning == 1){
printf("DevexecTask reentrant protection triggered\n");
return 1;
}
/*
* CheckExeList may cause waits and thus reentrant calls to
* this. Which can cause trouble
*/
self->taskRunning = 1;
iRet = CheckExeList(self);
self->taskRunning = 0;
self->lastRun = time(NULL);
switch(iRet)
{
case -1: /* some problem */
@ -1374,7 +1388,9 @@ static int testFinish(pExeList self){
{
if(iInterrupt > 1)
{
self->taskRunning = 1;
StopExe(self,"all");
self->taskRunning = 0;
}
#ifdef DEBUG
printf("DevExecTask found an error\n");

361
devser.c Normal file
View File

@ -0,0 +1,361 @@
#include <math.h>
#include "ascon.h"
#include "devser.h"
typedef struct DevAction {
struct DevAction *next;
void *data;
DevActionHandler *hdl;
DevPrio prio;
DevKillActionData *kill;
} DevAction;
typedef struct SchedHeader {
struct SchedHeader *next;
DevAction *actions; /* list of actions for given interval and prio */
DevAction *followingAction;
double interval;
double timeDue;
DevPrio prio;
} SchedHeader;
struct DevSer {
Ascon *asyncConn; /* connection */
DevAction *current;
int killCurrent;
DevAction *actions; /* the action queue */
SchedHeader *headers;
ErrMsg *errmsg;
int steps;
int stopTask;
};
static char *devPrio[NumberOfPRIO] = {
"null", "slow", "read", "progress", "write", "halt"
};
char *DevPrio2Text(DevPrio prio) {
if (prio <= 0 || prio >= NumberOfPRIO) {
prio = NullPRIO;
}
return devPrio[prio];
}
DevPrio DevText2Prio(char *text) {
DevPrio prio;
for (prio = 0; prio < NumberOfPRIO; prio++) {
if (strcasecmp(text, devPrio[prio]) == 0) return prio;
}
return NullPRIO;
}
static void DevFreeActionList(DevAction *actions) {
DevAction *victim;
while (actions != NULL) {
victim = actions;
actions = victim->next;
if (victim->kill != NULL) victim->kill(victim->data);
free(victim);
}
}
static void DevKillTask(void *ds) {
DevSer *devser = ds;
if (devser->stopTask) {
free(devser);
} else {
devser->stopTask = 1;
}
}
DevAction *DevNextAction(DevSer *devser) {
DevPrio prio;
double now;
SchedHeader *header;
devser->current = NULL;
if (devser->actions) {
prio = devser->actions->prio;
} else {
prio = NullPRIO;
}
now = DoubleTime();
for (header = devser->headers;
header != NULL && header->prio > prio;
header = header->next) {
if (header->followingAction == NULL) {
if (now >= header->timeDue) {
header->followingAction = header->actions;
if (header->interval <= 0) {
header->timeDue = now;
} else {
header->timeDue = (floor(now / header->interval) + 1)
* header->interval;
}
}
}
if (header->followingAction != NULL) {
devser->current = header->followingAction;
devser->killCurrent = 0;
header->followingAction = header->followingAction->next;
return devser->current;
}
}
if (devser->actions) {
devser->current = devser->actions;
devser->killCurrent = 1;
devser->actions = devser->actions->next;
}
return devser->current;
}
int DevQueueTask(void *ds) {
DevSer *devser = ds;
AsconStatus status;
DevAction *action;
char *sendData;
char *replyData;
if (devser->steps == 0) return 1;
if (devser->stopTask) {
return 0;
}
action = devser->current;
if (action == NULL) {
action = DevNextAction(devser);
}
while (action != NULL) {
status = AsconTask(devser->asyncConn);
if (status == AsconFailure) {
devser->errmsg = AsconGetErrList(devser->asyncConn);
} else if (status != AsconReady) {
return 1;
}
if (devser->steps > 0) { /* debugging mode */
devser->steps--;
}
if(status == AsconFailure){
replyData = devser->errmsg->text;
} else {
replyData = AsconRead(devser->asyncConn);
}
sendData = action->hdl(action->data, replyData);
if (sendData != NULL) {
AsconWrite(devser->asyncConn, sendData, 0);
return 1;
}
if (devser->killCurrent) {
if (action->kill != NULL) action->kill(action->data);
devser->killCurrent = 0;
free(action);
devser->current = NULL;
}
action = DevNextAction(devser);
}
return 1;
}
DevSer *DevMake(SConnection *con, int argc, char *argv[]) {
DevSer *devser = NULL;
Ascon *asyncConn = NULL;
asyncConn = AsconMake(con, argc, argv);
if (!asyncConn) {
return NULL;
}
devser = calloc(1, sizeof(*devser));
assert(devser);
devser->asyncConn = asyncConn;
devser->current = NULL;
devser->killCurrent = 0;
devser->actions = NULL;
devser->headers = NULL;
devser->stopTask = 0;
devser->steps = -1; /* no debugging by default */
TaskRegister(pServ->pTasker, DevQueueTask, NULL, DevKillTask, devser, 0);
return devser;
}
void DevDebugMode(DevSer *devser, int steps) {
devser->steps = steps;
}
DevAction *DevNewAction(void *data, DevActionHandler hdl,
DevKillActionData *killFunc, DevPrio prio) {
DevAction *action;
action = calloc(1, sizeof(*action));
assert(action);
action->data = data;
action->hdl = hdl;
action->kill = killFunc;
action->prio = prio;
action->next = NULL;
return action;
}
void DevKill(DevSer *devser) {
SchedHeader *h, *victim;
if (devser->asyncConn) {
AsconKill(devser->asyncConn);
}
DevFreeActionList(devser->actions);
h = devser->headers;
while (h != NULL) {
victim = h;
h = victim->next;
DevFreeActionList(victim->actions);
free(victim);
}
if (devser->stopTask) {
free(devser);
} else {
devser->stopTask = 1;
}
}
void DevQueue(DevSer *devser, void *actionData, DevPrio prio,
DevActionHandler hdl, DevActionMatch *matchFunc,
DevKillActionData *killFunc) {
DevAction *action, **ptr2Last;
DevAction *new;
if (prio <= NullPRIO) prio = NullPRIO + 1;
if (prio >= NumberOfPRIO) prio = NumberOfPRIO - 1;
ptr2Last = &devser->actions;
for (action = devser->actions; action != NULL && action->prio >= prio; action = action->next) {
if (action->hdl == hdl && matchFunc(actionData, action->data)) {
return; /* there is already an identical action */
}
ptr2Last = &action->next;
}
new = DevNewAction(actionData, hdl, killFunc, prio);
new->next = action;
*ptr2Last = new;
}
int DevUnschedule(DevSer *devser, void *actionData,
DevActionHandler hdl, DevActionMatch *matchFunc) {
SchedHeader *header = NULL;
DevAction **ptr2Last = NULL;
DevAction *action = NULL;
int cnt=0;
/* scan through all headers */
for (header = devser->headers; header != NULL; header = header->next) {
ptr2Last = &header->actions;
for (action = header->actions; action != NULL; action = *ptr2Last) {
if (action->hdl == hdl && matchFunc(actionData, action->data)) {
if (action == header->followingAction) {
/* advance followingAction if equal*/
header->followingAction = action->next;
}
if (action == devser->current) {
devser->current = NULL;
devser->killCurrent = 0; /* should already be 0 */
}
cnt++;
/* remove from list */
*ptr2Last = action->next;
if (action->kill != NULL) action->kill(action->data);
free(action);
} else {
ptr2Last = &action->next;
}
}
}
return cnt;
}
int DevSchedule(DevSer *devser, void *actionData,
DevPrio prio, double interval,
DevActionHandler hdl, DevActionMatch *matchFunc,
DevKillActionData *killFunc) {
SchedHeader *header = NULL;
SchedHeader **ptr2LastHeader = NULL;
SchedHeader *newHeader;
DevAction *action = NULL;
DevAction **ptr2Last = NULL;
DevAction *newAction;
int ret;
if (prio <= NullPRIO) prio = NullPRIO + 1;
if (prio >= NumberOfPRIO) prio = NumberOfPRIO - 1;
ret = DevUnschedule(devser, actionData, hdl, matchFunc);
newAction = DevNewAction(actionData, hdl, killFunc, prio);
/* find matching header */
ptr2LastHeader = &devser->headers;
for (header = devser->headers; header != NULL; header = *ptr2LastHeader) {
if (header->prio == newAction->prio && header->interval == interval) {
/* append new action at the tail */
ptr2Last = &header->actions;
for (action = header->actions; action != NULL; action=action->next) {
ptr2Last = &action->next;
}
*ptr2Last = newAction;
assert(newAction->next == NULL);
return ret;
} else if (header->prio < newAction->prio ||
(header->prio == newAction->prio
&& header->interval > interval)) {
break;
}
if (header->actions == NULL) {
/* remove empty header */
*ptr2LastHeader = header->next;
free(header);
} else {
ptr2LastHeader = &header->next;
}
}
/* insert new header */
newHeader = calloc(1, sizeof(*newHeader));
assert(newHeader);
newHeader->actions = newAction;
newHeader->followingAction = NULL;
newHeader->prio = newAction->prio;
newHeader->interval = interval;
newHeader->next = header;
newHeader->timeDue = DoubleTime() + interval;
*ptr2LastHeader = newHeader;
return ret;
}
int DevRemoveAction(DevSer *devser, void *actionData) {
SchedHeader *header = NULL;
DevAction **ptr2Last = NULL;
DevAction *action = NULL;
int cnt=0;
/* Remove current action, if matched. If a reply is pending, the next action will
get the reply. But as in the inital state no reply is expected, this should not harm. */
action = devser->current;
if (action != NULL && actionData == action->data) {
if (devser->killCurrent) {
if (action->kill != NULL) action->kill(action->data);
devser->killCurrent = 0;
free(action);
}
devser->current = NULL;
}
/* remove from queue */
ptr2Last = &devser->actions;
for (action = devser->actions; action != NULL; action = action->next) {
if (actionData == action->data) {
cnt++;
/* remove from list */
*ptr2Last = action->next;
if (action->kill != NULL) action->kill(action->data);
free(action);
} else {
ptr2Last = &action->next;
}
}
return cnt++;
}

123
devser.h Normal file
View File

@ -0,0 +1,123 @@
#ifndef DEVSER_H
#define DEVSER_H
/** \file
* \brief Device Serializer
*/
typedef struct DevSer DevSer;
/** \brief The action handler to be called
* \param actionData the data stored with the action
* \param lastReply the last reply or NULL when no command was
* sent in the last action
* \return the command to be sent or NULL if no command has to be sent
*/
typedef char *DevActionHandler(void *actionData, char *lastReply);
/** \brief Check if an action matches the call data
* \param callData the callers data
* \param actionData the action data
* \return 1 on a match, 0 on no match
*/
typedef int DevActionMatch(void *callData, void *actionData);
/** \brief Kill ActionData
* \param actionData action data
*/
typedef void DevKillActionData(void *actionData);
/** \brief possible priorities.
* NullPRIO and NumberOfPRIO must not be used as priority
*/
typedef enum {
NullPRIO, SlowPRIO, ReadPRIO, ProgressPRIO, WritePRIO, HaltPRIO, NumberOfPRIO
} DevPrio;
/** \brief Make a new device serializer and async connection.
* \param con the SICS connection (for error messages)
* \param argc the number of args for specifying the protocol
* \param argv the args
* \return the created device serializer or NULL on failure
*/
DevSer *DevMake(SConnection *con, int argc, char *argv[]);
/** \brief put the device serializer into debug mode
* \param devser the device serializer
* \param steps the number of steps to be executed or -1 for disable debugging mode
*/
void DevDebugMode(DevSer *devser, int steps);
/** \brief Kill the contents of the device serializer and its async connection.
*
* The data structure itself is killed at some time later
* \param devser the device serializer
*/
void DevKill(DevSer *devser);
/** \brief Queue an action
*
* If a matching action with the same action handler
* exists already, no new action is queued.
* \param devser the device serializer
* \param actionData the action data
* \param prio the priority
* \param hdl the action handler
* \param matchFunc the match function
* \param killFunc the action data kill function (called from DevKill and
* after the action has finished, i.e. when hdl returned NULL)
* or NULL if no kill function is needed.
*/
void DevQueue(DevSer *devser, void *actionData, DevPrio prio,
DevActionHandler hdl, DevActionMatch *matchFunc,
DevKillActionData *killFunc) ;
/** \brief Schedule a periodic action
*
* If a matching action exists already,
* it is overwritten with a possibly changed interval and priority.
* \param devser the device serializer
* \param actionData the action data
* \param prio the priority
* \param interval the interval in seconds (0 is allowed)
* \param hdl the action handler
* \param matchFunc the match function (callData must be of the same type as actionData)
* \param killFunc the action data kill function (called from DevKill and
* from DevUnschedule) or NULL if no kill function is needed.
* \return 0 when this was a new action, > 0 when an action was overwritten
*/
int DevSchedule(DevSer *devser, void *actionData,
DevPrio prio, double interval,
DevActionHandler hdl, DevActionMatch *matchFunc,
DevKillActionData *killFunc);
/** \brief Unschedule matching actions
* \param devser the device serializer
* \param callData the callers data to be as first argument of the match function
* \param hdl the action handler
* \param matchFunc the match function (callData does not need to have the same type as actionData)
* \return the number of unscheduled actions
*/
int DevUnschedule(DevSer *devser, void *actionData,
DevActionHandler hdl, DevActionMatch *matchFunc);
/** \brief remove action from the serializer
* \param devser the device serializer
* \param actionData the action data to be compared for a match
*/
int DevRemoveAction(DevSer *devser, void *actionData);
/** \brief Convert integer priority to text
* \param prio
* \return text
*/
char *DevPrio2Text(DevPrio prio);
/** \brief Convert text priority to integer
* \param text
* \return prio
*/
DevPrio DevText2Prio(char *text);
#endif

View File

@ -336,7 +336,7 @@ static int DiffScanTask(void *pData){
check for interrupt
*/
if(SCGetInterrupt(self->scanObject->pCon) >= eAbortScan){
pCount->pDriv->Halt(pCount->pDriv);
pCount->pCountInt->Halt(pCount);
pVar->pInter->Halt(pVar->pObject);
SicsWait(1);
finish = 0;

View File

@ -66,6 +66,10 @@ above and restores SICS to the state it was in when the status was saved with
read.
</p>
<p>
<b>restore listerr</b> prints the list of lines which caused errors during the
last restore.
</p>
<p>
<b>killfile</b> decrements the data number used for SICS file writing
and thus consequently overwrites the last datafile. This is useful
when useless data files have been created during tests. As this is

View File

@ -94,15 +94,23 @@ In order to calculate a UB matrix a list of reflections must be maintained. This
This section covers the parameters and commands to use to make the module do calculations
for you.
<dl>
<dt>tasbub const ki | kf
<dt>tasbub const ki | kf | elastic
<dd>Sets a parameter to determine if KI or KF is fixed when the energy transfer en is
being driven. Allowed values: ki, kf
being driven. Allowed values: ki, kf, elastic. In elastic mode the analyzer is
disregarded. This is useful for two circle diffractometers.
<dt>tasub const
<dd>Prints if ki or kf is fixed.
<dt>tasub ss
<dd>Prints the sample scattering sense.
<dt>tasub ss 1 | -1
<dd>Sets the sample scattering sense. Allowed values are either 1 or -1.
<dt>tasub silent 0 | 1
<dd>Prints or sets the silent flag. If this is 0, the messages Driving motor ..
from .. to .. are suppressed.</dd>
<dt>tasub outofplane 0 | 1
<dd>Prints or sets the outofplane flag. If this flag is 0, the instrument will stay
in the scattering plane and not move out of it. This is here in order to protect those
bloody magnets which cannot be tilted.</dd>
<dt>tasub makeub r1 r2
<dd>Calculate a new UB matrix from the current cell constants and the entries r1 and r2 in
the reflection list. r1 and r2 are integer numbers. This command will not only print the
@ -143,7 +151,7 @@ The virtual motor qm implements <b>powder mode</b>. In this mode, only the sampl
respective positions. THis is commonly used to analyze the energy transfer of powder samples.
</p>
<p>
There is another important command:
There are other important command:
<dl>
<dt>tasub update
<dd>This command will force a recalculation of the current Q-E position for the virtual
@ -151,6 +159,9 @@ motors from angles. Normally tasub will take care of this. However, if any of th
motors are moved directly or manualy, this command might be required. The SICS dr
wrapper command, however, even takes care of this.
</dl>
<dt>tasub updatetargets
<dd>This command makes the QE targets macth the current position. This is
useful after initialization in the instrument.tcl file.</dd>
</p>
<h3>Internal Commands</h3>
<p>

68
errormsg.c Normal file
View File

@ -0,0 +1,68 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "errormsg.h"
/* compare two strings for euqality, ignoring text within square brackets */
int ErrEqual(char *str1, char *str2) {
char *p;
while (*str1 != '\0' || *str2 != '\0') {
if (*str1 != *str2) {
return 0;
}
if (*str1 == '[') {
str1 = strchr(str1, ']');
str2 = strchr(str2, ']');
if (str1 == NULL || str2 == NULL) {
return str1 == str2;
}
}
str1++;
str2++;
}
return 1;
}
ErrMsg *ErrPutMsg(ErrMsg *dump, char *fmt, ...) {
ErrMsg *m = NULL;
ErrMsg **last = NULL;
va_list ap;
char buf[256];
char *text = NULL;
int l;
va_start(ap, fmt);
l = vsnprintf(buf, sizeof buf, fmt, ap);
va_end(ap);
if (l < sizeof buf) {
text = buf;
} else {
/* assuming we have a C99 conforming snprintf and need a larger buffer */
text = calloc(l, 1);
va_start(ap, fmt);
vsnprintf(text, l, fmt, ap);
va_end(ap);
}
last = &dump;
for (m = dump; m != NULL; m = m->next) {
if (ErrEqual(text, m->text)) {
*last = m->next; /* remove found item from list */
break;
}
last = &m->next;
}
if (m == NULL) { /* make a new item */
if (text == buf) text = strdup(buf);
m = calloc(1, sizeof(*m));
m->text = text;
m->cnt = 1;
} else {
if (text != buf) free(text);
m->cnt++;
}
m->next = dump;
time(&m->last);
return m;
}

32
errormsg.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef ERRORMSG_H
#define ERRORMSG_H
#include <time.h>
/** \file
* \brief Error message collection
*/
/** \brief Error message item
*/
typedef struct ErrMsg {
struct ErrMsg *next;
char *text; /**< the message text */
int cnt; /**< count */
time_t last; /**< time of last message */
} ErrMsg;
/** \brief Put a formatted message to the error message list
*
* The error message list contains only one entry for all messages
* with the same text, storing only the count and the last used time.
* Characters within square brackets are not taken into account
* when comparing messages.
* The new message is always at the head of the list.
*
* \param dump the error message list
* \param fmt the format for the message
* \return the new error message list head
*/
ErrMsg *ErrPutMsg(ErrMsg *dump, char *fmt, ...);
#endif

View File

@ -100,7 +100,7 @@
self->start = time(NULL);
self->lastt = 0;
self->iWarned = 0;
SCSave(&self->conn, pCon);
self->conn = SCSave(pCon, self->conn);
/* try at least three times to do it */
for(i = 0; i < 3; i++)
@ -292,9 +292,9 @@
if (self->lastt > 0) { /* increase tol for hysteresis */
tol=tol*1.1001;
}
tmo = (int)(ObVal(self->pParam, SETTLE));
if(fDelta <= tol) /* inside tolerance */
{
tmo = (int)(ObVal(self->pParam, SETTLE));
if (self->lastt <= 0) /* lastt negative: -seconds already waited */
{
self->lastt += now;
@ -319,9 +319,11 @@
else
{
if (self->lastt > 0) { /* save time already waited */
if (tmo > 0) {
sprintf(pBueffel,"%s outside tolerance, settling time suspended",
self->pName);
SCWrite(pCon,pBueffel,eWarning);
}
self->lastt -= now;
}
notifyStatus(self, pCon, HWBusy);
@ -382,17 +384,15 @@ static void ErrWrite(char *txt, SCStore *conn)
pExe = GetExecutor();
pCon = GetExeOwner(pExe);
if (!pCon)
{
pCon = SCLoad(conn);
}
if(pCon)
if (pCon)
{
SCWrite(pCon,txt,eWarning);
}
else
{
ServerWriteGlobal(txt,eWarning);
pCon = SCStorePush(conn);
SCWrite(pCon, txt, eWarning);
SCStorePop(conn);
}
}
/*-----------------------------------------------------------------------*/
@ -406,7 +406,7 @@ static void ErrReport(pEVControl self)
{
sprintf(pBueffel,"WARNING: %s is out of range by %g",
self->pName,fDelta);
ErrWrite(pBueffel, &self->conn);
ErrWrite(pBueffel, self->conn);
self->iWarned = 1;
}
}
@ -479,7 +479,7 @@ static void ErrReport(pEVControl self)
snprintf(pBueffel,255,
"ERROR: %s while processing errorscript for %s",
pTcl->result,self->pName);
ErrWrite(pBueffel, &self->conn);
ErrWrite(pBueffel, self->conn);
}
/*
assume that everything is fine again after the script
@ -493,7 +493,7 @@ static void ErrReport(pEVControl self)
snprintf(pBueffel,255,
"ERROR: script error handling requested for %s, but no script given",
self->pName);
ErrWrite(pBueffel, &self->conn);
ErrWrite(pBueffel, self->conn);
}
return 1;
@ -523,7 +523,7 @@ static void ErrReport(pEVControl self)
ErrReport(self);
ErrWrite("Running to safe value", &self->conn);
ErrWrite("Running to safe value", self->conn);
self->pDriv->SetValue(self->pDriv, ObVal(self->pParam,SAFEVALUE));
self->eMode = EVIdle;
self->iWarned = 0;
@ -615,7 +615,7 @@ static void ErrReport(pEVControl self)
{
sprintf(pBueffel,"Environment device %s back in tolerances again",
self->pName);
ErrWrite(pBueffel, &self->conn);
ErrWrite(pBueffel, self->conn);
self->iWarned = 0;
}
return 1;
@ -796,6 +796,7 @@ static void ErrReport(pEVControl self)
pRes->pName = strdup(pName);
pRes->eMode = EVIdle;
pRes->iWarned = 0;
pRes->conn = NULL;
/* a terminal error gives a -1 in iRet */
if(iRet < 0)
@ -868,6 +869,10 @@ static void ErrReport(pEVControl self)
{
free(self->runScript);
}
if (self->conn != NULL)
{
SCStoreFree(self->conn);
}
free(self);
}
/*--------------------------------------------------------------------------*/

View File

@ -41,7 +41,7 @@
int iWarned;
int iTcl;
int iStop;
SCStore conn;
SCStore *conn;
char *creationArgs;
char *runScript;
void *pPrivate;

View File

@ -52,13 +52,13 @@ $\langle$evdata {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int iWarned;@\\
\mbox{}\verb@ int iTcl;@\\
\mbox{}\verb@ int iStop;@\\
\mbox{}\verb@ SCStore conn;@\\
\mbox{}\verb@ SCStore *conn;@\\
\mbox{}\verb@ char *creationArgs;@\\
\mbox{}\verb@ char *runScript;@\\
\mbox{}\verb@ void *pPrivate;@\\
\mbox{}\verb@ void (*KillPrivate)(void *pData);@\\
\mbox{}\verb@ } EVControl;@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -123,7 +123,7 @@ $\langle$evdriv {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ void *pPrivate;@\\
\mbox{}\verb@ void (*KillPrivate)(void *pData);@\\
\mbox{}\verb@ } EVDriver;@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -208,7 +208,7 @@ $\langle$dvfunc {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -286,7 +286,7 @@ See the documentation for commands understood.
\mbox{}\verb@#include "varlog.h"@\\
\mbox{}\verb@@$\langle$dvfunc {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
@ -315,7 +315,7 @@ See the documentation for commands understood.
\mbox{}\verb@#define SETTLE 8@\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\langle$evdata {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
@ -340,7 +340,7 @@ See the documentation for commands understood.
\mbox{}\verb@/*-------------------- life & death of a driver --------------------------*/@\\
\mbox{}\verb@ pEVDriver CreateEVDriver(int argc, char *argv[]);@\\
\mbox{}\verb@ void DeleteEVDriver(pEVDriver pDriv);@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]

View File

@ -47,7 +47,7 @@ used by EVControl:
int iWarned;
int iTcl;
int iStop;
SCStore conn;
SCStore *conn;
char *creationArgs;
char *runScript;
void *pPrivate;

15
event.h
View File

@ -1,5 +1,5 @@
#line 103 "event.w"
#line 100 "event.w"
/*----------------------------------------------------------------------------
E V E N T
@ -14,15 +14,15 @@
#ifndef SICSEVENT
#define SICSEVENT
#line 14 "event.w"
#line 13 "event.w"
int Text2Event(char *pText);
#line 116 "event.w"
#line 113 "event.w"
#line 21 "event.w"
#line 20 "event.w"
#define VALUECHANGE 0
#define MOTDRIVE 1
@ -48,19 +48,20 @@
#define STSTART 21
#define STEND 22
#line 118 "event.w"
#line 115 "event.w"
/*--------------- Signals for the Signalfunction of each task ------------*/
#line 87 "event.w"
#line 82 "event.w"
#define SICSINT 300
#define SICSBROADCAST 301
#define TOKENGRAB 302
#define TOKENRELEASE 303
#define COMLOG 304
#define CRONLIST 305
#line 121 "event.w"
#line 118 "event.w"
#endif

View File

@ -17,7 +17,7 @@ $\langle$eFunc {\footnotesize ?}$\rangle\equiv$
\begin{list}{}{} \item
\mbox{}\verb@@\\
\mbox{}\verb@ int Text2Event(char *pText);@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -56,7 +56,9 @@ $\langle$VE {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@#define STATUS 18@\\
\mbox{}\verb@#define POSITION 19@\\
\mbox{}\verb@#define HDBVAL 20@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@#define STSTART 21@\\
\mbox{}\verb@#define STEND 22@\\
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -113,7 +115,8 @@ $\langle$VSIG {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@#define TOKENGRAB 302@\\
\mbox{}\verb@#define TOKENRELEASE 303@\\
\mbox{}\verb@#define COMLOG 304@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@#define CRONLIST 305@\\
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -130,6 +133,7 @@ data is the string to send.
\item[TOKENGRAB] A connection has successfully grabbed the control token.
\item[TOKENRELEASE] A connection has released the control token.
\item[COMLOG] A command log message. This is to implement listen mode to the command log.
\item[CRONLIST] Tell the cron tasks to inform about themselves.
\end{description}
\begin{flushleft} \small
\begin{minipage}{\linewidth} \label{scrap4}
@ -156,7 +160,7 @@ data is the string to send.
\mbox{}\verb@/*--------------- Signals for the Signalfunction of each task ------------*/@\\
\mbox{}\verb@@$\langle$VSIG {\footnotesize ?}$\rangle$\verb@ @\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]

View File

@ -39,6 +39,8 @@ if the event code is not known, else the apropriate event code.
#define STATUS 18
#define POSITION 19
#define HDBVAL 20
#define STSTART 21
#define STEND 22
@}
\begin{description}
\item[VALUECHANGE] This is a variable changing its value. As event data a pointer to the
@ -83,6 +85,7 @@ possible codes are defined.
#define TOKENGRAB 302
#define TOKENRELEASE 303
#define COMLOG 304
#define CRONLIST 305
@}
\begin{description}
\item[SICSINT] An interrupt has ocurred. The signal data is the interrupt
@ -92,6 +95,7 @@ data is the string to send.
\item[TOKENGRAB] A connection has successfully grabbed the control token.
\item[TOKENRELEASE] A connection has released the control token.
\item[COMLOG] A command log message. This is to implement listen mode to the command log.
\item[CRONLIST] Tell the cron tasks to inform about themselves.
\end{description}
@o event.h -d @{
/*----------------------------------------------------------------------------

16
exe.w
View File

@ -89,6 +89,19 @@ The interface to this buffer system comprises:
*/
int exeBufProcess(pExeBuf self, SicsInterp *pSics,
SConnection *pCon, pICallBack pCall, int echo);
/**
* Process an exe buffer, but store commands causing errors in a list.
* This is used for restoring status files.
* @@param self The exe buffer to process
* @@param pSics The SICS interpreter to use for processing
* @@param pCon The connection object providing the environment for
* processing this buffer.
* @@param errCommandList A lld string list for storing commands which
* had errors.
* @@return 1 on success, 0 on error
*/
int exeBufProcessErrList(pExeBuf self, SicsInterp *pSics,
SConnection *pCon, int errCommandList);
/**
* retrieves the executing range
* @@param self The exe buffer to query
@ -174,6 +187,9 @@ int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int runExeBatchBuffer(void *pData, SConnection *pCon, SicsInterp *pSics,
char *name);
pDynString findBatchFile(SicsInterp *pSics, char *name);
int exeHdbBuffer(SConnection *pCon,
SicsInterp *pSics, char *name);
int exeHdbNode(pHdb exeNode, SConnection *pCon);
@}
@o exeman.i -d @{

View File

@ -11,6 +11,7 @@
#include <stdio.h>
#include <assert.h>
#include <tcl.h>
#include "lld_str.h"
#include "fortify.h"
#include "sics.h"
#include "exebuf.h"
@ -90,7 +91,9 @@ int exeBufLoad(pExeBuf self, char *filename){
return 0;
}
while(fgets(line,255,fd) != NULL){
status = exeBufAppend(self,line);
/* Do not use exeBufAppend here. Lines longer than 255 would get
newline characters within the line */
status = DynStringConcat(self->bufferContent,line);
if(status != 1){
fclose(fd);
return 0;
@ -166,13 +169,17 @@ int exeBufProcess(pExeBuf self, SicsInterp *pSics,
self->lineno = 0;
pTcl = InterpGetTcl(pSics);
if(pCall != NULL){
InvokeCallBack(pCall,BATCHSTART,self->name);
}
if (echo) {
SCsetMacro(pCon,0);
}
while((command = findBlockEnd(self)) != NULL){
if(pCall != NULL){
InvokeCallBack(pCall,BATCHAREA,NULL);
}
cmd = GetCharArray(command);
if (echo) {
@ -223,7 +230,53 @@ int exeBufProcess(pExeBuf self, SicsInterp *pSics,
SCSetInterrupt(pCon,eContinue);
}
}
if(pCall != NULL){
InvokeCallBack(pCall,BATCHEND,self->name);
}
return 1;
}
/*---------------------------------------------------------------------*/
int exeBufProcessErrList(pExeBuf self, SicsInterp *pSics,
SConnection *pCon, int errList){
pDynString command = NULL;
Tcl_Interp *pTcl = NULL;
int status;
static int weWantLogging = 1;
char *cmd;
char cmdName[128];
char *error;
char msg[132];
char *ende;
int l;
assert(self);
assert(pSics);
self->start = 0;
self->end = -1;
self->lineno = 0;
pTcl = InterpGetTcl(pSics);
while((command = findBlockEnd(self)) != NULL){
cmd = GetCharArray(command);
status = Tcl_Eval(pTcl,cmd);
if(status != TCL_OK){
LLDstringAppend(errList,cmd);
error = (char *)Tcl_GetStringResult(pTcl);
snprintf(msg, sizeof msg, "#ERR: %s\n", error);
LLDstringAppend(errList,msg);
}
DeleteDynString(command);
if(SCGetInterrupt(pCon) >= eAbortBatch){
SCWrite(pCon,"ERROR: batch processing interrupted",eError);
SetStatus(eEager);
return 0;
} else {
SCSetInterrupt(pCon,eContinue);
}
}
return 1;
}
/*------------------------------------------------------------------------*/

View File

@ -1,5 +1,5 @@
#line 210 "exe.w"
#line 226 "exe.w"
/**
* Buffer handling code for the Exe Buffer batch file processing
@ -63,6 +63,19 @@
*/
int exeBufProcess(pExeBuf self, SicsInterp *pSics,
SConnection *pCon, pICallBack pCall, int echo);
/**
* Process an exe buffer, but store commands causing errors in a list.
* This is used for restoring status files.
* @param self The exe buffer to process
* @param pSics The SICS interpreter to use for processing
* @param pCon The connection object providing the environment for
* processing this buffer.
* @param errCommandList A lld string list for storing commands which
* had errors.
* @return 1 on success, 0 on error
*/
int exeBufProcessErrList(pExeBuf self, SicsInterp *pSics,
SConnection *pCon, int errCommandList);
/**
* retrieves the executing range
* @param self The exe buffer to query
@ -89,7 +102,7 @@
*/
char *exeBufName(pExeBuf self);
#line 223 "exe.w"
#line 239 "exe.w"
#endif

View File

@ -1,5 +1,5 @@
#line 201 "exe.w"
#line 217 "exe.w"
/*--------------------------------------------------------------------
Internal header file for the exe buffer module. Do not edit. This is
@ -16,6 +16,6 @@ typedef struct __EXEBUF{
int lineno;
} ExeBuf;
#line 206 "exe.w"
#line 222 "exe.w"

223
exeman.c
View File

@ -22,7 +22,9 @@
#include "exebuf.h"
#include "exeman.i"
#include "exeman.h"
#include "sicshipadaba.h"
#include "commandlog.h"
#include "protocol.h"
/*-------------------------------------------------------------------*/
static void KillExeMan(void *data){
pExeMan self = (pExeMan)data;
@ -252,6 +254,210 @@ static int runBatchBuffer(pExeMan self, SConnection *pCon,
return status;
}
/*-------------------------------------------------------------------*/
static char bufferNode[512];
static int SCHdbWrite(SConnection *self, char *message, int outCode){
pHdb node = NULL;
char pBueffel[512];
commandContext cc;
hdbValue v;
pDynString val = NULL;
writeFunc defWrite = NULL;
cc = SCGetContext(self);
node = GetHipadabaNode(GetHipadabaRoot(),cc.deviceID);
if(node == NULL || strstr(cc.deviceID,bufferNode) == NULL){
/*
* this means the deviceId is wrong and the output is for another
* operation.
*/
defWrite = GetProtocolWriteFunc(self);
if(defWrite == NULL){
defWrite = SCNormalWrite;
}
defWrite(self,message,outCode);
return 1;
}
SCFileWrite(self,message,outCode);
if(SCinMacro(self) && (outCode != eError && outCode != eWarning) ){
return 1;
}
v = MakeHdbText(strdup(""));
GetHipadabaPar(node,&v,NULL);
v.dataType = HIPTEXT;
val = CreateDynString(128,128);
if(val == NULL){
WriteToCommandLog("INTERNAL ERROR>>",
"No memory to append to log in SCHdbWrite");
return 0;
}
if(v.v.text != NULL){
DynStringConcat(val,v.v.text);
if(strrchr(v.v.text,(int)'\n') == NULL && strlen(v.v.text) > 1){
DynStringConcatChar(val,'\n');
}
}
DynStringConcat(val,message);
if(strrchr(message,(int)'\n') == NULL && strlen(message) > 1){
DynStringConcatChar(val,'\n');
}
if(v.v.text != NULL){
free(v.v.text);
}
v.v.text = GetCharArray(val);
UpdateHipadabaPar(node,v,NULL);
DeleteDynString(val);
return 1;
}
/*--------------------------------------------------------------------*/
int exeHdbNode(pHdb exeNode, SConnection *pCon){
char pBueffel[512], *name = NULL;
pHdb node = NULL, log = NULL;
pExeBuf buffer = NULL;
hdbValue v;
int status;
commandContext cc;
writeFunc oldWrite;
/*
* clear log buffer
*/
log = GetHipadabaNode(exeNode,"log");
if(log == NULL){
SCWrite(pCon,"ERROR: Hdb node not found or in wrong format",eError);
return 0;
}
v = MakeHdbText(strdup(""));
UpdateHipadabaPar(log,v,pCon);
/*
* prepare context
*/
name = GetHipadabaPath(log);
cc = SCGetContext(pCon);
strncpy(cc.deviceID, name,255);
strncpy(bufferNode,name,511);
/*
* load commands into buffer
*/
node = GetHipadabaNode(exeNode,"commands");
if(node == NULL){
SCWrite(pCon,"ERROR: Hdb node not found or in wrong format",eError);
return 0;
}
GetHipadabaPar(node,&v,pCon);
if(v.dataType != HIPTEXT || v.v.text == NULL){
SCWrite(pCon,"ERROR: Hdb node is of wrong type or contains no data",eError);
return 0;
}
buffer = exeBufCreate(name);
if(!buffer){
SCWrite(pCon,"ERROR: out of memory creating batch buffer",eError);
return 0;
}
exeBufAppend(buffer,v.v.text);
strncpy(bufferNode,name,511);
oldWrite = SCGetWriteFunc(pCon);
SCSetWriteFunc(pCon,SCHdbWrite);
SCPushContext2(pCon,cc);
status = exeBufProcess(buffer,pServ->pSics,pCon,NULL,0);
SCSetWriteFunc(pCon,oldWrite);
SCPopContext(pCon);
exeBufDelete(buffer);
free(name);
if(strlen(log->value.v.text) < 2){
v = MakeHdbText(strdup("OK\n"));
UpdateHipadabaPar(log,v,pCon);
ReleaseHdbValue(&v);
}
return status;
}
/*--------------------------------------------------------------------*/
static int runHdbBuffer(pExeMan self, SConnection *pCon,
SicsInterp *pSics, char *name){
char pBueffel[512];
pExeBuf buffer = NULL;
pHdb node = NULL;
hdbValue v;
int status;
commandContext cc;
writeFunc oldWrite;
if(!SCMatchRights(pCon,usUser)) {
return 0;
}
/*
* clear log buffer
*/
snprintf(pBueffel,511,"%s/log",name);
node = GetHipadabaNode(GetHipadabaRoot(),pBueffel);
if(node == NULL){
SCWrite(pCon,"ERROR: Hdb node not found or in wrong format",eError);
return 0;
}
v = MakeHdbText(strdup(""));
UpdateHipadabaPar(node,v,pCon);
/*
* prepare context
*/
cc = SCGetContext(pCon);
strcpy(cc.deviceID, pBueffel);
/*
* load commands into buffer
*/
snprintf(pBueffel,511,"%s/commands",name);
node = GetHipadabaNode(GetHipadabaRoot(),pBueffel);
if(node == NULL){
SCWrite(pCon,"ERROR: Hdb node not found or in wrong format",eError);
return 0;
}
GetHipadabaPar(node,&v,pCon);
if(v.dataType != HIPTEXT || v.v.text == NULL){
SCWrite(pCon,"ERROR: Hdb node is of wrong type or contains no data",eError);
return 0;
}
buffer = exeBufCreate(name);
if(!buffer){
SCWrite(pCon,"ERROR: out of memory creating batch buffer",eError);
return 0;
}
exeBufAppend(buffer,v.v.text);
strncpy(bufferNode,name,511);
oldWrite = SCGetWriteFunc(pCon);
SCSetWriteFunc(pCon,SCHdbWrite);
SCPushContext2(pCon,cc);
self->exeStackPtr++;
DynarPut(self->exeStack,self->exeStackPtr,buffer);
status = exeBufProcess(buffer,pSics,pCon,self->pCall,self->echo);
self->exeStackPtr--;
SCSetWriteFunc(pCon,oldWrite);
SCPopContext(pCon);
return status;
}
/*--------------------------------------------------------------------*/
int exeHdbBuffer(SConnection *pCon,
SicsInterp *pSics, char *name){
pExeMan self = (pExeMan)FindCommandData(pSics,"exe","ExeManager");
if(self != NULL){
return runHdbBuffer(self,pCon,pSics,name);
}
return 0;
}
/*-------------------------------------------------------------------*/
int runExeBatchBuffer(void *pData, SConnection *pCon,
SicsInterp *pSics, char *name){
int status, oldEcho;
@ -863,11 +1069,14 @@ static int printBuffer(pExeMan self, SConnection *pCon,
DeleteDynString(filePath);
return 0;
}
DeleteDynString(filePath);
SCStartBuffering(pCon);
while(fgets(pLine,511,fd) != NULL){
SCWrite(pCon,pLine,eValue);
}
fclose(fd);
DeleteDynString(filePath);
filePath = SCEndBuffering(pCon);
SCWrite(pCon,GetCharArray(filePath),eValue);
return 1;
}
/*========================== run stack ===============================*/
@ -1090,6 +1299,16 @@ int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
SCPrintf(pCon, eValue, "exe echo = %d", self->echo);
}
return 1;
}else if(strcmp(argv[1],"runhdb") == 0){
if (argc < 2) {
SCWrite(pCon,"ERROR: require path to root of queue node",eError);
SCSendOK(pCon);
}
status = runHdbBuffer(self,pCon,pSics,argv[2]);
if(self->exeStackPtr < 0){
SCWrite(pCon,"EXE TERMINATED",eWarning);
}
return status;
} else {
status = runBatchBuffer(self,pCon,pSics,pBufferName);
if(self->exeStackPtr < 0){

View File

@ -16,5 +16,8 @@ int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int runExeBatchBuffer(void *pData, SConnection *pCon, SicsInterp *pSics,
char *name);
pDynString findBatchFile(SicsInterp *pSics, char *name);
int exeHdbBuffer(SConnection *pCon,
SicsInterp *pSics, char *name);
int exeHdbNode(pHdb exeNode, SConnection *pCon);
#endif

View File

@ -1,12 +1,12 @@
#line 179 "exe.w"
#line 195 "exe.w"
/*-------------------------------------------------------------------
Internal header file for the exe manager module. Do not edit. This
is automatically generated from exe.w
-------------------------------------------------------------------*/
#line 138 "exe.w"
#line 151 "exe.w"
typedef struct __EXEMAN{
pObjectDescriptor pDes;
@ -20,5 +20,5 @@ typedef struct __EXEMAN{
int echo;
}ExeMan, *pExeMan;
#line 184 "exe.w"
#line 200 "exe.w"

305
fomerge.c
View File

@ -17,6 +17,8 @@
Mark Koennecke, March 2000
extended to support nxscripted file writing: Mark Koennecke, May 2004
extended to support GTSE, Mark Koennecke, May 2008
--------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
@ -27,6 +29,7 @@
#include "fortify.h"
#include "scan.h"
#include "fitcenter.h"
#include "sicsdata.h"
static pFit fitter = NULL;
@ -594,10 +597,100 @@ static int putSum(SicsInterp *pSics, SConnection *pCon,
return status;
}
/*---------------------------------------------------------------------*/
static int putElastic(SicsInterp *pSics, SConnection *pCon,
pNXScript pNexus, char *alias, float fElastic)
{
static int TOFLambda(SicsInterp *pSics, SConnection *pCon,
int argc, char *argv[]){
int status, iTime, iDet, i;
const float *fTimeBin = NULL;
int *sum = NULL;
long *lSum = NULL;
pHistMem pMem = NULL;
float fCenter, fFWHM, fStdDev, fVal;
float fMon, fData, distMonoDet, distFermiDet, tdiff, lambda;
pMem = (pHistMem)FindCommandData(pSics,"hm1","HistMem");
if(pMem == NULL)
{
SCWrite(pCon,
"ERROR: need lower detector bank for lambda calculation",
eError);
return 0;
}
/**
* locate elastic position in data
*/
fTimeBin = GetHistTimeBin(pMem,&iTime);
iDet = getFMdim(LOWER);
sum = calculateTimeSum(GetHistogramPointer(pMem,pCon),iDet,iTime);
if(!sum)
{
SCWrite(pCon,"ERROR: out of memory calculating lambda",
eError);
return 0;
}
if(fitter == NULL)
{
fitter = CreateFitCenter(NULL);
if(!fitter)
{
SCWrite(pCon,"ERROR: cannot allocate fitting structure",eError);
return 0;
}
}
/*
copy sum to make compiler happy
*/
lSum = (long *)malloc(iTime*sizeof(long));
if(lSum == NULL)
{
SCWrite(pCon,"ERROR: out of memory in TOFLambda",eError);
free(sum);
return 0;
}
for(i = 0; i < iTime; i++)
{
lSum[i] = sum[i];
}
status = CalculateFitFromData(fitter,(float *)fTimeBin,lSum,iTime);
if(status < 0)
{
SCWrite(pCon,"ERROR: no peak in data",eError);
free(sum);
free(lSum);
return 0;
}
GetFitResults(fitter,&fCenter,&fStdDev,&fFWHM,&fVal);
fData = fCenter;
/*
* locate elastic position in tofmon
*/
GetHistogram(pMem, pCon, 0, iTime*iDet, iTime*(iDet+1),
sum, iTime*sizeof(HistInt));
for(i = 0; i < iTime; i++)
{
lSum[i] = sum[i];
}
status = CalculateFitFromData(fitter,(float *)fTimeBin,lSum,iTime);
GetFitResults(fitter,&fCenter,&fStdDev,&fFWHM,&fVal);
fMon = fCenter;
free(sum);
free(lSum);
/*
* calculate
*/
distFermiDet = 3000.;
distMonoDet = distFermiDet - 215.7;
tdiff = fData - fMon;
lambda = tdiff/(252.78*distMonoDet*.001);
SCPrintf(pCon,eValue, "toflambda = %f", lambda);
return 1;
}
/*---------------------------------------------------------------------*/
static float calcElastic(SicsInterp *pSics, SConnection *pCon)
{
int status, iTime, iDet, i;
const float *fTimeBin = NULL;
int *sum = NULL;
@ -611,7 +704,7 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon,
SCWrite(pCon,
"ERROR: need middle detector bank for elastic peak calculation",
eError);
return NX_ERROR;
return -1.;
}
fTimeBin = GetHistTimeBin(pMem,&iTime);
iDet = getFMdim(MIDDLE);
@ -620,7 +713,7 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon,
{
SCWrite(pCon,"ERROR: out of memory calculating elastic peak position",
eError);
return NX_ERROR;
return -1;
}
if(fitter == NULL)
{
@ -628,7 +721,7 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon,
if(!fitter)
{
SCWrite(pCon,"ERROR: cannot allocate fitting structure",eError);
return NX_ERROR;
return -1.;
}
}
/*
@ -639,7 +732,7 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon,
{
SCWrite(pCon,"ERROR: out of memory in putElastic",eError);
free(sum);
return NX_ERROR;
return -1.;
}
for(i = 0; i < iTime; i++)
{
@ -647,38 +740,180 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon,
}
status = CalculateFitFromData(fitter,(float *)fTimeBin,lSum,iTime);
free(lSum);
if(status != 1)
{
SCWrite(pCon,"WARNING: problem locating elastic peak",eWarning);
}
GetFitResults(fitter,&fCenter,&fStdDev,&fFWHM,&fVal);
fVal = fCenter - fElastic;
if(fVal < 0.)
fVal = - fVal;
/* bad value, leave at theoretical value */
if(fVal > 10.)
{
SCWrite(pCon,
"WARNING: bad fit result, using theoretical elastic peak position",
eWarning);
}
else
{
fElastic = fCenter;
}
free(sum);
return fCenter;
}
/*---------------------------------------------------------------------*/
#define ABS(x) (x < 0 ? -(x) : (x))
static int putElastic(SicsInterp *pSics, SConnection *pCon,
pNXScript pNexus, char *alias, float fElastic)
{
float fCalc;
int status;
fCalc = calcElastic(pSics,pCon);
if(ABS(fElastic -fCalc) < 20) {
fElastic = fCalc;
}
status = NXDputalias(pNexus->fileHandle, pNexus->dictHandle,alias,
&fElastic);
return status;
}
/*----------------------------------------------------------------------*/
static int FMputTTH(SConnection *pCon, int argc, char *argv[]){
pSICSData data = NULL;
int length = -1, i;
float *tthData = NULL;
if(argc < 4){
SCWrite(pCon,"ERROR: insufficient no of arguments to FMputTTH",
eError);
return 0;
}
data = (pSICSData)FindCommandData(pServ->pSics,argv[3],"SICSData");
if(data == NULL){
SCWrite(pCon,"ERROR: SICSData object not found", eError);
return 0;
}
if(strcmp(argv[2],"upper") == 0)
{
length = getFMdim(UPPER);
tthData = getFMBankTheta(UPPER);
}
else if(strcmp(argv[2],"middle") == 0)
{
length = getFMdim(MIDDLE);
tthData = getFMBankTheta(MIDDLE);
}
else if(strcmp(argv[2],"lower") == 0)
{
length = getFMdim(LOWER);
tthData = getFMBankTheta(LOWER);
}
else if(strcmp(argv[2],"merged") == 0)
{
length = getFMdim(MERGED);
tthData = getFMBankTheta(MERGED);
}
else
{
SCWrite(pCon,"ERROR: requested two_theta for invalid detector bank",
eError);
return 0;
}
if(length < 0 || tthData == NULL){
SCWrite(pCon,"ERROR: requested two_theta for invalid detector bank",
eError);
return 0;
}
clearSICSData(data);
for(i = 0; i < length; i++){
setSICSDataFloat(data,i,tthData[i]);
}
SCSendOK(pCon);
return 1;
}
/*---------------------------------------------------------------------*/
static int FMcopyMerged(SConnection *pCon, int argc, char *argv[]){
pSICSData data = NULL;
int i, length;
HistInt *hmData = NULL;
if(argc < 3){
SCWrite(pCon,"ERROR: insufficient no of arguments to FMcopyMerged",
eError);
return 0;
}
data = (pSICSData)FindCommandData(pServ->pSics,argv[2],"SICSData");
if(data == NULL){
SCWrite(pCon,"ERROR: SICSData object not found", eError);
return 0;
}
if(!updateHMFMData(pServ->pSics, pCon)){
SCWrite(pCon,"ERROR: not enough HM's to merge or bad names in fomerge.c",
eError);
return 0;
}
clearSICSData(data);
length = getFMdim(MERGED)*getFMdim(TIMEBIN);
hmData = getFMBankPointer(MERGED);
if(hmData == NULL){
SCWrite(pCon,"ERROR: merged data not available", eError);
return 0;
}
for(i = 0; i < length; i++){
setSICSDataInt(data,i,hmData[i]);
}
SCSendOK(pCon);
return 1;
}
/*---------------------------------------------------------------------*/
static int FMcopyMergedSum(SConnection *pCon, int argc, char *argv[]){
pSICSData data = NULL;
int i, length, tbin, j, row;
HistInt *hmData = NULL, *sumData = NULL;
if(argc < 3){
SCWrite(pCon,"ERROR: insufficient no of arguments to FMcopyMerged",
eError);
return 0;
}
data = (pSICSData)FindCommandData(pServ->pSics,argv[2],"SICSData");
if(data == NULL){
SCWrite(pCon,"ERROR: SICSData object not found", eError);
return 0;
}
if(!updateHMFMData(pServ->pSics, pCon)){
SCWrite(pCon,"ERROR: not enough HM's to merge or bad names in fomerge.c",
eError);
return 0;
}
clearSICSData(data);
length = getFMdim(MERGED);
tbin = getFMdim(TIMEBIN);
hmData = getFMBankPointer(MERGED);
if(hmData == NULL){
SCWrite(pCon,"ERROR: merged data not available", eError);
return 0;
}
sumData = malloc(tbin*sizeof(int));
if(sumData == NULL){
SCWrite(pCon,"ERROR: out-of-memory in FMcopyMergedSum", eError);
return 0;
}
memset(sumData,0,tbin*sizeof(int));
for(j = 0; j < length; j++){
row = j*tbin;
for(i = 0; i < tbin; i++){
sumData[i] += hmData[row+i];
}
}
for(i = 0; i < tbin; i++){
setSICSDataInt(data,i,sumData[i]);
}
free(sumData);
SCSendOK(pCon);
return 1;
}
/*-----------------------------------------------------------------------
Usage:
focusmerge puttwotheta nxscriptmod bankname alias
focusmerge puttth bankname sicsdataname
focusmerge copymerged sicsdataname
focusmerge copymergedsum sicsdataname
focusmerge putmerged nxscriptmod alias
focusmerge putsum nxscriptmod bankname alias
focusmerge putelastic nxscriptmod alias theoelastic
focusmerge toflambda
focusmerge elastic
nxscriptmod = name of the nxscript module used for writing, must be open
alias = The alias under which to write the data item
@ -700,6 +935,26 @@ int FocusMergeAction(SConnection *pCon, SicsInterp *pSics, void *pData,
}
strtolower(argv[1]);
if(strcmp(argv[1],"puttth") == 0){
return FMputTTH(pCon,argc,argv);
}
if(strcmp(argv[1],"copymerged") == 0){
return FMcopyMerged(pCon,argc,argv);
}
if(strcmp(argv[1],"copymergedsum") == 0){
return FMcopyMergedSum(pCon,argc,argv);
}
if(strcmp(argv[1],"toflambda") == 0){
return TOFLambda(pSics, pCon,argc,argv);
}
if(strcmp(argv[1],"elastic") == 0){
fElastic = calcElastic(pSics,pCon);
SCPrintf(pCon,eValue,"tofelastic = %f", fElastic);
return 1;
}
if(strcmp(argv[1],"puttwotheta") == 0)
{
if(argc < 4)

622
genericcontroller.c Normal file
View File

@ -0,0 +1,622 @@
/**
* This is a generic controller for devices in SICS. It is configurable via Tcl
* scripts.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, November 2007
*/
#include <stdlib.h>
#include <assert.h>
#include <tcl.h>
#include <sics.h>
#include <macro.h>
#include <sicshipadaba.h>
#include <sicsobj.h>
#include <dynstring.h>
#include <genericcontroller.h>
/*--------------------------------------------------------------------------*/
static hdbCallbackReturn GenConSetCallback(pHdb node, void *userData,
pHdbMessage message){
pSICSOBJ self = (pSICSOBJ)userData;
SConnection *pCon = NULL;
pGenController priv = NULL;
char command[1024];
char value[80];
int status, privilege;
pDynString data;
pHdbDataMessage mm = NULL;
assert(self != NULL);
if((mm = GetHdbSetMessage(message)) == NULL){
return hdbContinue;
}
priv = (pGenController)self->pPrivate;
pCon = mm->callData;
/*
* check rights
*/
memset(value,0,80);
if(GetHdbProperty(node,"priv",value,80) && pCon != NULL){
privilege = usInternal;
if(strcmp(value,"manager") == 0){
privilege = usMugger;
}
if(strcmp(value,"user") == 0){
privilege = usUser;
}
if(!SCMatchRights(pCon,privilege)){
return hdbAbort;
}
}
/*
* check writeCommand
*/
memset(value,0,80);
GetHdbProperty(node,"writeCommand",value,80);
if(strlen(value) < 2){
if(pCon != NULL){
SCWrite(pCon,"ERROR: parameter is read-only",eError);
return hdbAbort;
}
return hdbAbort;
}
/*
* check status
*/
memset(value,0,80);
GetHdbProperty(node,"status",value,80);
if(strstr(value,"idle") == NULL){
return hdbAbort;
}
SetHdbProperty(node,"status","setting");
data = formatValue(*(mm->v), node);
if(data != NULL){
SetHdbProperty(node,"target",GetCharArray(data));
DeleteDynString(data);
}
/*
* issue command
*/
if(priv->enqueueNodeHead != NULL){
priv->enqueueNodeHead(self,pCon,node);
} else {
if(pCon != NULL){
SCWrite(pCon,"ERROR: generic controller NOT configured",
eError);
}
return hdbAbort;
}
return hdbContinue;
}
/*--------------------------------------------------------------------------*/
static hdbCallbackReturn GenConGetCallback(pHdb node, void *userData,
pHdbMessage message){
pSICSOBJ self = (pSICSOBJ)userData;
SConnection *pCon = NULL;
pGenController priv = NULL;
char command[1024];
char value[256];
int status, privilege;
pHdbDataMessage mm = NULL;
assert(self != NULL);
if((mm = GetHdbGetMessage(message)) == NULL){
return hdbContinue;
}
pCon = mm->callData;
priv = (pGenController)self->pPrivate;
/*
* check status
*/
memset(value,0,80);
GetHdbProperty(node,"status",value,80);
if(strstr(value,"idle") == NULL){
return hdbContinue;
}
SetHdbProperty(node,"status","getting");
/*
* check readCommand
*/
memset(value,0,256);
GetHdbProperty(node,"readCommand",value,255);
if(strlen(value) < 2){
return hdbAbort;
} else {
if(priv->enqueueNode != NULL){
priv->enqueueNode(self,pCon, node);
} else {
if(pCon != NULL){
SCWrite(pCon,"ERROR: generic controller connection NOT configured",
eError);
}
return hdbAbort;
}
}
/*
* Upper Level GetHipadabaPar will automatically return the
* node value. Which should have been updated through an update
* during the execution of enqueueNode
*/
return hdbContinue;
}
/*---------------------------------------------------------------------------*/
static pHdb MakeGenConPar(pSICSOBJ self, char *name, int type, int length){
pHdb result = NULL;
pHdbCallback kalle = NULL;
result = MakeHipadabaNode(name,type,length);
if(result == NULL){
return NULL;
}
kalle = MakeHipadabaCallback(GenConSetCallback,
self,
NULL);
if(kalle == NULL){
return NULL;
}
AppendHipadabaCallback(result,kalle);
kalle = MakeHipadabaCallback(GenConGetCallback,
self,
NULL);
if(kalle == NULL){
return NULL;
}
AppendHipadabaCallback(result,kalle);
SetHdbProperty(result,"priv","manager");
SetHdbProperty(result,"readCommand","");
SetHdbProperty(result,"writeCommand","");
SetHdbProperty(result,"replyCommand","");
SetHdbProperty(result,"status","idle");
return result;
}
/*---------------------------------------------------------------------------*/
static int MakeGenPar(pSICSOBJ self, SConnection *pCon,
char *argv[], int argc){
char buffer[2048];
int type, length = 1;
pHdb node = NULL , parent;
char *pPtr = NULL;
if(argc < 5){
snprintf(buffer,2048,"ERROR: insufficient arguments to %s makepar",
argv[0]);
SCWrite(pCon,buffer, eError);
return 0;
}
type = convertHdbType(argv[4]);
if(argc > 5){
length = atoi(argv[5]);
}
strncpy(buffer,argv[3],2047);
pPtr = strrchr(buffer,'/');
if(pPtr == NULL){
node = MakeGenConPar(self, argv[3], type, length);
parent = self->objectNode;
} else {
*pPtr = '\0';
pPtr++;
node = MakeGenConPar(self, pPtr, type, length);
parent = GetHipadabaNode(self->objectNode,buffer);
}
if(node == NULL || parent == NULL){
SCWrite(pCon,"ERROR: failed to create node or parent not found",
eError);
return 0;
}
AddHipadabaChild(parent, node, pCon);
SCSendOK(pCon);
return 1;
}
/*=============================== ==========================================
* This stuff is for the Tcl - AsynQueue implementation of GenericController
* ==========================================================================*/
typedef struct {
pHdb node;
pSICSOBJ obj;
SConnection *pCon;
pGenController priv;
pAsyncUnit assi;
pAsyncTxn trans;
commandContext comCon;
char replyCommand[2048];
} GenContext, *pGenContext;
/*--------------------------------------------------------------------------
* This is called by AsyncQueue when a reply has been received.
* -------------------------------------------------------------------------*/
static int GenConTxnHandler(pAsyncTxn pTxn){
pGenContext genCon = NULL;
char reply[10240];
genCon = (pGenContext)pTxn->cntx;
assert(genCon != NULL);
memset(reply,0,10240*sizeof(char));
switch(pTxn->txn_state){
case ATX_NULL:
case ATX_ACTIVE:
return 1;
break;
case ATX_TIMEOUT:
strcpy(reply,"TIMEOUT");
break;
case ATX_DISCO:
strcpy(reply,"DISCONNECTED");
break;
case ATX_COMPLETE:
strncpy(reply,pTxn->inp_buf,10240);
break;
}
if(genCon->pCon != NULL){
SCPushContext2(genCon->pCon, genCon->comCon);
}
genCon->priv->replyCallback(genCon->obj, genCon->pCon,
genCon->node, genCon->replyCommand, reply, strlen(reply));
if(genCon->pCon != NULL){
SCPopContext(genCon->pCon);
}
free(genCon);
return 1;
}
/*--------------------------------------------------------------------------*/
static char *formatCommand(pHdb node, SConnection *pCon){
pDynString com = NULL;
char value[512];
Tcl_Interp *pTcl = NULL;
int status;
com = CreateDynString(256,128);
if(com == NULL){
return NULL;
}
memset(value,0,512);
GetHdbProperty(node,"status",value,512);
if(strstr(value,"set") != NULL){
memset(value,0,512);
GetHdbProperty(node,"writeCommand",value,512);
DynStringConcat(com,value);
DynStringConcatChar(com,' ');
memset(value,0,512);
GetHdbProperty(node,"target",value,512);
DynStringConcat(com,value);
} else {
memset(value,0,512);
GetHdbProperty(node,"readCommand",value,512);
DynStringConcat(com,value);
}
pTcl = InterpGetTcl(pServ->pSics);
if(pCon != NULL){
MacroPush(pCon);
}
status = Tcl_Eval(pTcl, GetCharArray(com));
if(pCon != NULL){
MacroPop();
}
DeleteDynString(com);
if(status != TCL_OK){
SetHdbProperty(node,"result", (char *)Tcl_GetStringResult(pTcl));
return NULL;
}
return strdup(Tcl_GetStringResult(pTcl));
}
/*--------------------------------------------------------------------------*/
static pGenContext PrepareToEnque(pSICSOBJ self, SConnection *pCon, pHdb node){
pGenContext result = NULL;
char *command = NULL;
pGenController priv = NULL;
priv = (pGenController)self->pPrivate;
assert(priv != NULL);
command = formatCommand(node, pCon);
if(command == NULL){
return NULL;
}
result = malloc(sizeof(GenContext));
if(result == NULL){
return NULL;
}
memset(result,0,sizeof(GenContext));
if(!GetHdbProperty(node,"replyCommand",result->replyCommand,2048)){
if(pCon != NULL){
SCWrite(pCon,"ERROR: no replyCommand found",eError);
}
free(result);
return NULL;
}
result->assi = AsyncUnitFromQueue((pAsyncQueue)priv->comContext);
if(result->assi == NULL){
return NULL;
}
result->trans = AsyncUnitPrepareTxn(result->assi,
command,strlen(command),
GenConTxnHandler,
result,
2048);
if(result->trans == NULL){
return NULL;
}
result->node = node;
result->priv = priv;
result->obj = self;
result->pCon = pCon;
priv->comError = GCOK;
result->comCon = SCGetContext(pCon);
free(command);
return result;
}
/*---------------------------------------------------------------------------*/
static int AsyncEnqueueNode(pSICSOBJ self, SConnection *pCon, pHdb node){
pGenContext genCon = NULL;
genCon = PrepareToEnque(self, pCon, node);
if(genCon == NULL){
return 0;
}
return AsyncUnitEnqueueTxn(genCon->assi, genCon->trans);
}
/*---------------------------------------------------------------------------*/
static int AsyncEnqueueNodeHead(pSICSOBJ self, SConnection *pCon, pHdb node){
pGenContext genCon = NULL;
genCon = PrepareToEnque(self, pCon, node);
if(genCon == NULL){
return 0;
}
return AsyncUnitEnqueueHead(genCon->assi, genCon->trans);
}
/*---------------------------------------------------------------------------*/
static int AsyncReply(pSICSOBJ self, SConnection *pCon, pHdb node,
char *replyCommand, char *reply, int replylen){
pDynString com = NULL;
Tcl_Interp *pTcl;
int status;
SetHdbProperty(node,"result",reply);
com = CreateDynString(256,128);
if(com == NULL){
return 0;
}
DynStringConcat(com, replyCommand);
DynStringConcat(com," \"");
DynStringConcat(com, reply);
DynStringConcat(com,"\"\0");
if(pCon != NULL){
MacroPush(pCon);
}
pTcl = InterpGetTcl(pServ->pSics);
status = Tcl_Eval(pTcl,GetCharArray(com));
if(pCon != NULL){
MacroPop();
}
DeleteDynString(com);
if(status != TCL_OK){
SetHdbProperty(node,"lastError",(char *)Tcl_GetStringResult(pTcl));
}
return status;
}
/*============= GenController Object Functions ==============================*/
static int ConnectAsync(pSICSOBJ self, SConnection *pCon,
char *argv[], int argc){
pGenController priv = NULL;
pAsyncQueue assi = NULL;
char buffer[2048];
pAsyncUnit uni = NULL;
priv = (pGenController)self->pPrivate;
assert(priv != NULL);
if(argc < 4){
snprintf(buffer,2048,"ERROR: insufficient arguments to %s asynconnect",
argv[0]);
SCWrite(pCon,buffer, eError);
return 0;
}
assi = (pAsyncQueue)FindCommandData(pServ->pSics, argv[3],"AsyncQueue");
if(assi == NULL){
snprintf(buffer,2048,"ERROR: %s not found or no AsyncQueue", argv[3]);
SCWrite(pCon,buffer,eError);
return 0;
}
priv->comContext = assi;
priv->killComContext = NULL; /* not ours, cleaned up by AsyncQueue module */
priv->enqueueNode = AsyncEnqueueNode;
priv->enqueueNodeHead = AsyncEnqueueNodeHead;
priv->replyCallback = AsyncReply;
priv->comError = GCOK;
/*
* This unit is solely for the purpose of receiving event notifications
*/
uni = AsyncUnitFromQueue(assi);
SCSendOK(pCon);
return 1;
}
/*---------------------------------------------------------------------------*/
int GenControllerConfigure(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]){
pSICSOBJ controller = NULL;
pGenController self = NULL;
char buffer[2048];
if(argc < 3){
snprintf(buffer,2048,"ERROR: insufficient arguments to %s", argv[0]);
SCWrite(pCon,buffer,eError);
return 0;
}
controller = (pSICSOBJ)FindCommandData(pSics,argv[2], "GenericController");
if(controller == NULL){
snprintf(buffer,2048,"ERROR: controller %s not found", argv[2]);
SCWrite(pCon,buffer,eError);
return 0;
}
strtolower(argv[1]);
if(strcmp(argv[1],"makepar") == 0){
return MakeGenPar(controller,pCon,argv,argc);
} else if(strcmp(argv[1],"asynconnect") == 0){
return ConnectAsync(controller, pCon, argv, argc);
} else {
SCWrite(pCon,"ERROR: argument to GenControllerConfigure not found",
eError);
return 0;
}
return 1;
}
/*---------------------------------------------------------------------------*/
static void killGeneric(void *data){
pGenController self = (pGenController)data;
if(self == NULL){
return;
}
if(self->comContext != NULL && self->killComContext != NULL){
self->killComContext(self->comContext);
}
free(self);
}
/*---------------------------------------------------------------------------*/
static int EnqueFunc(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar){
pGenController priv = NULL;
pHdb node = NULL;
char buffer[512];
priv = (pGenController)self->pPrivate;
assert(priv != NULL);
assert(nPar >= 1);
node = GetHipadabaNode(self->objectNode,par[0]->value.v.text);
if(node == NULL){
snprintf(buffer,511,"ERROR: node %s to enqueue not found",
par[0]->value.v.text);
SCWrite(pCon,buffer,eError);
return 0;
}
if(priv->enqueueNode != NULL){
priv->enqueueNode(self, pCon, node);
} else {
SCWrite(pCon,"ERROR: GenController NOT configured",eError);
return 0;
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int EnqueHeadFunc(pSICSOBJ self, SConnection *pCon, Hdb commandNode,
pHdb par[], int nPar){
pGenController priv = NULL;
pHdb node = NULL;
char buffer[512];
priv = (pGenController)self->pPrivate;
assert(priv != NULL);
assert(nPar >= 1);
node = GetHipadabaNode(self->objectNode,par[0]->value.v.text);
if(node == NULL){
snprintf(buffer,511,"ERROR: node %s to enqueue not found",
par[0]->value.v.text);
SCWrite(pCon,buffer,eError);
return 0;
}
if(priv->enqueueNodeHead != NULL){
priv->enqueueNodeHead(self, pCon, node);
} else {
SCWrite(pCon,"ERROR: GenController NOT configured",eError);
return 0;
}
return 1;
}
/*---------------------------------------------------------------------------*/
int GenControllerFactory(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]){
pSICSOBJ pNew = NULL;
pGenController priv = NULL;
hdbValue funcValue, textValue;
pHdb node = NULL;
char line[132];
int status;
if(argc < 2){
SCWrite(pCon,
"ERROR: insufficient number of arguments to GenControllerFactrory",
eError);
return 0;
}
priv = malloc(sizeof(GenController));
if(priv == NULL){
SCWrite(pCon,"ERROR: out of memory in GenControllerFactory",
eError);
return 0;
}
memset(priv,0,sizeof(GenController));
pNew = MakeSICSOBJ(argv[1],"GenericController");
if(pNew == NULL){
SCWrite(pCon,"ERROR: out of memory in GenControllerFactory",
eError);
return 0;
}
pNew->pPrivate = priv;
pNew->KillPrivate = killGeneric;
textValue = MakeHdbText("Undefined");
funcValue = MakeHdbFunc((voidFunc *)EnqueFunc);
node = MakeSICSHdbPar("enqueue",usUser, funcValue);
AddSICSHdbPar(node,"node",usUser,textValue);
AppendHipadabaCallback(node,MakeSICSFuncCallback(pNew));
AddHipadabaChild(pNew->objectNode,node,NULL);
funcValue = MakeHdbFunc((voidFunc *)EnqueHeadFunc);
node = MakeSICSHdbPar("enqueuehead",usUser, funcValue);
AddSICSHdbPar(node,"node",usUser,textValue);
AppendHipadabaCallback(node,MakeSICSFuncCallback(pNew));
AddHipadabaChild(pNew->objectNode,node,NULL);
status = AddCommand(pSics,
argv[1],
InvokeSICSOBJ,
KillSICSOBJ,
pNew);
if(status != 1){
KillSICSOBJ(pNew);
SCPrintf(pCon,eError,"ERROR: failed create duplicate command %s", argv[1]);
return 0;
}
SCSendOK(pCon);
return 1;
}

37
genericcontroller.h Normal file
View File

@ -0,0 +1,37 @@
/**
* This is a generic controller for devices in SICS. In its default configuration it
* will be configurable via Tcl scripts and used AsynqQueue for communication. But
* it is suitably generic to support other mechanisms as well.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, November 2007
*/
#ifndef GENERICCONTROLLER_H_
#define GENERICCONTROLLER_H_
#include <asyncqueue.h>
#include <sicshipadaba.h>
#define GCTIMEOUT 5001
#define GCDISCONNECT 5002
#define GCOK 5000
#define GCRECONNECT 5003
#define GCRETRY 5004
typedef struct {
int (*enqueueNode)(pSICSOBJ self, SConnection *pCon, pHdb node);
int (*enqueueNodeHead)(pSICSOBJ self, SConnection *pCon, pHdb node);
int (*replyCallback)(pSICSOBJ self, SConnection *pCon, pHdb node,
char *replyCommand, char *reply, int replylen);
void *comContext;
void (*killComContext)(void *data);
int comError;
}GenController, *pGenController;
/*---------------------------------------------------------------------------*/
int GenControllerFactory(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]);
/*---------------------------------------------------------------------------*/
int GenControllerConfigure(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]);
#endif /*GENERICCONTROLLER_H_*/

19
geninter.c Normal file
View File

@ -0,0 +1,19 @@
/**
* This is the implementation of various SICS internal interfaces based on
* parameters in a generic controller.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, November 2007
*/
#include <stdlib.h>
#include <assert.h>
#include <sics.h>
#include <sicshipadaba.h>
/*---------------------------------------------------------------------------*/
int GenDrivableFactory(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]){
return 1;
}

19
geninter.h Normal file
View File

@ -0,0 +1,19 @@
/**
* This is the implementation of various SICS internal interfaces based on
* parameters in a generic controller.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, November 2007
*/
#ifndef GENINTER_H_
#define GENINTER_H_
/**
* make a drivable parameter:
* Usage:
* MakeGenDrivable name par-node control-node
*/
int GenDrivableFactory(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]);
#endif /*GENINTER_H_*/

497
hdbqueue.c Normal file
View File

@ -0,0 +1,497 @@
/**
* This is the new Hipadaba based queuing system in support of the MountainGum
* user interface.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, July 2007
*/
#include <stdlib.h>
#include <assert.h>
#include <sics.h>
#include "sicsobj.h"
#include "hdbqueue.h"
#include "sicshipadaba.h"
#include "dynstring.h"
#include "exeman.h"
#include "macro.h"
/*--------------------------------------------------------------------------*/
typedef struct {
int iStop;
int isRunning;
SConnection *pCon;
}HdbQueue, *pHdbQueue;
/*--------------------------------------------------------------------------*/
static pHdbCallback CopyCallbackChain(pHdbCallback source){
pHdbCallback current = NULL;
pHdbCallback result = NULL;
pHdbCallback head = NULL;
pHdbCallback tail = NULL;
current = source;
while(current != NULL){
result = MakeHipadabaCallback(current->userCallback,
current->userData,
NULL,
current->id,
current->internalID);
if(head == NULL){
head = result;
tail = result;
} else {
tail->next = result;
result->previous = tail;
tail = result;
}
current = current->next;
}
return head;
}
/*---------------------------------------------------------------------------*/
static pHdb MakeNewEntry(char *name, pHdbCallback update){
pHdb entry = NULL, child = NULL;
hdbValue v;
v = MakeHdbText("Undefined");
entry = MakeHipadabaNode(name,HIPNONE, 1);
entry->updateCallbacks = CopyCallbackChain(update);
child = MakeSICSHdbPar("description",usUser,v);
child->updateCallbacks = CopyCallbackChain(update);
AddHipadabaChild(entry,child,NULL);
child = MakeSICSHdbPar("commands",usUser,v);
child->updateCallbacks = CopyCallbackChain(update);
AddHipadabaChild(entry,child,NULL);
child = MakeSICSHdbPar("log",usUser,v);
child->updateCallbacks = CopyCallbackChain(update);
AddHipadabaChild(entry,child,NULL);
return entry;
}
/*---------------------------------------------------------------------------*/
static int EnqueFunc(pSICSOBJ self, SConnection *pCon, Hdb commandNode,
pHdb par[], int nPar){
pHdb entry = NULL;
pHdb work = NULL;
char name[80];
hdbValue v;
if(nPar < 1){
SCWrite(pCon,"ERROR: internal: not enough parameters to EnqueFunc",eError);
return 0;
}
/*
* new entry
*/
memset(&v,0,sizeof(hdbValue));
work = GetHipadabaNode(self->objectNode,"control/maxEntry");
assert(work != NULL);
snprintf(name,80,"%3.3d", work->value.v.intValue);
entry = MakeNewEntry(name, work->updateCallbacks);
if(entry == NULL){
SCWrite(pCon,"ERROR: out of memory in EnqueFunc",eError);
return 0;
}
/*
* Update maxEntry
*/
cloneHdbValue(&work->value,&v);
v.v.intValue++;
UpdateHipadabaPar(work,v,pCon);
work = GetHipadabaNode(self->objectNode,"queue");
assert(work != NULL);
AddHipadabaChild(work, entry, pCon);
/*
* save description
*/
work = GetHipadabaNode(entry,"description");
assert(work != NULL);
UpdateHipadabaPar(work,par[0]->value,pCon);
return 1;
}
/*---------------------------------------------------------------------------*/
static int AddCmdData(pSICSOBJ self, SConnection *pCon, Hdb comNode,
pHdb par[], int nPar){
pHdb work = NULL;
pHdb commandNode = NULL;
char name[80];
pDynString txt = NULL;
if(nPar < 1){
SCWrite(pCon,"ERROR: internal: not enough parameters to AddCmdData",eError);
return 0;
}
work = GetHipadabaNode(self->objectNode,"control/maxEntry");
assert(work != NULL);
snprintf(name,80,"queue/%3.3d/commands", work->value.v.intValue-1);
commandNode = GetHipadabaNode(self->objectNode,name);
if(commandNode == NULL){
SCWrite(pCon,"ERROR: Internal error in AddCommand",eError);
return 0;
}
txt = CreateDynString(80,80);
if(strstr(commandNode->value.v.text,"Undefined") == NULL){
DynStringCopy(txt,commandNode->value.v.text);
}
DynStringConcat(txt,par[0]->value.v.text);
DynStringConcat(txt,"\n");
free(commandNode->value.v.text);
commandNode->value.v.text = strdup(GetCharArray(txt));
NotifyHipadabaPar(commandNode,pCon);
DeleteDynString(txt);
return 1;
}
/*--------------------------------------------------------------------------*/
static void sequentialNames(pHdb obj,SConnection *pCon){
pHdb work = NULL;
pHdb current = NULL;
int count = 0;
char name[80];
work = GetHipadabaNode(obj,"queue");
assert(work != NULL);
current = work->child;
while(current != NULL){
snprintf(name,80,"%3.3d",count);
if(current->name != NULL){
free(current->name);
}
current->name = strdup(name);
count++;
current = current->next;
}
InvokeCallbackChain(work->treeChangeCallbacks,work,pCon,work->value);
work = GetHipadabaNode(obj,"control/maxEntry");
assert(work != NULL);
work->value.v.intValue = count;
NotifyHipadabaPar(work,pCon);
}
/*---------------------------------------------------------------------------*/
static int Dequeue(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar){
pHdb work = NULL;
char name[80];
pHdbQueue priv = (pHdbQueue)self->pPrivate;
if(priv->isRunning == 1){
SCWrite(pCon,"ERROR: cannot dequeue while running",eError);
return 0;
}
if(nPar < 1){
SCWrite(pCon,"ERROR: internal: not enough parameters to Dequeue",eError);
return 0;
}
snprintf(name,80,"queue/%3.3d", par[0]->value.v.intValue);
work = GetHipadabaNode(self->objectNode,name);
if(work != NULL){
DeleteHipadabaNode(work,pCon);
sequentialNames(self->objectNode, pCon);
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
static int Clean(pSICSOBJ self, SConnection *pCon,Hdb commandNode,
pHdb par[], int nPar){
int i;
pHdb current = NULL, queue = NULL;
pHdb currentEntry = NULL, tmp = NULL;
pHdbQueue priv = (pHdbQueue)self->pPrivate;
if(priv->isRunning == 1){
SCWrite(pCon,"ERROR: cannot clean while running",eError);
return 0;
}
currentEntry = GetHipadabaNode(self->objectNode,"control/currentEntry");
queue = GetHipadabaNode(self->objectNode,"queue");
current = queue->child;
for(i = 0; i < currentEntry->value.v.intValue; i++){
if(current != NULL){
tmp = current->next;
DeleteNodeData(current);
current = tmp;
}
}
queue->child = tmp;
currentEntry->value.v.intValue = 0;
sequentialNames(self->objectNode, pCon);
NotifyHipadabaPar(currentEntry,pCon);
return 1;
}
/*---------------------------------------------------------------------------*/
static int CleanAll(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar){
int i;
pHdb current = NULL, queue = NULL;
pHdb currentEntry = NULL, tmp;
pHdbQueue priv = (pHdbQueue)self->pPrivate;
if(priv->isRunning == 1){
SCWrite(pCon,"ERROR: cannot clear queue while executing",eError);
return 0;
}
currentEntry = GetHipadabaNode(self->objectNode,"control/currentEntry");
queue = GetHipadabaNode(self->objectNode,"queue");
current = queue->child;
while(current != NULL){
tmp = current->next;
DeleteNodeData(current);
current = tmp;
}
queue->child = NULL;
currentEntry->value.v.intValue = 0;
sequentialNames(self->objectNode, pCon);
NotifyHipadabaPar(currentEntry,pCon);
return 1;
}
/*----------------------------------------------------------------------------*/
static int QueueTask(void *pData){
pSICSOBJ self = (pSICSOBJ)pData;
int status, pos;
pHdb work = NULL;
pHdb exeNode = NULL;
pHdb max = NULL;
char name[80];
pHdbQueue priv = (pHdbQueue)self->pPrivate;
if(priv->iStop == 1){
priv->isRunning = 0;
return 0;
}
work = GetHipadabaNode(self->objectNode,"control/currentEntry");
max = GetHipadabaNode(self->objectNode,"control/maxEntry");
assert(work != NULL && max != NULL);
pos = work->value.v.intValue;
snprintf(name,80,"queue/%3.3d", pos);
exeNode = GetHipadabaNode(self->objectNode,name);
if(exeNode != NULL){
MacroPush(priv->pCon);
exeHdbNode(exeNode, priv->pCon);
MacroPop();
}
if(priv->iStop == 1 || SCGetInterrupt(priv->pCon) != eContinue){
priv->isRunning = 0;
return 0;
}
pos++;
work->value.v.intValue = pos;
NotifyHipadabaPar(work,priv->pCon);
if(pos >= max->value.v.intValue){
priv->isRunning = 0;
return 0;
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int Start(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar){
pHdbQueue priv = (pHdbQueue)self->pPrivate;
priv->iStop = 0;
priv->pCon = pCon;
if(priv->isRunning == 1){
SCWrite(pCon,"ERROR: Hdbqueue is already running",eError);
return 0;
}
priv->isRunning = 1;
TaskRegister(pServ->pTasker,
QueueTask,
NULL,
NULL,
self,
10);
return 1;
}
/*---------------------------------------------------------------------------*/
static int Restart(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar){
pHdbQueue priv = (pHdbQueue)self->pPrivate;
pHdb maxCurrent = NULL;
maxCurrent = GetHipadabaNode(self->objectNode,"control/currentEntry");
if(maxCurrent != NULL){
maxCurrent->value.v.intValue = 0;
NotifyHipadabaPar(maxCurrent,pCon);
}
return Start(self,pCon,commandNode,par,nPar);
}
/*---------------------------------------------------------------------------*/
static int Stop(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar){
pHdbQueue priv = (pHdbQueue)self->pPrivate;
priv->iStop = 1;
return 1;
}
/*----------------------------------------------------------------------------*/
static int Move(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar){
pHdb moveNode = NULL;
pHdb insertNode = NULL;
pHdb prevNode = NULL, queueNode = NULL;
pHdb tmp;
char name[80];
pHdbQueue priv = (pHdbQueue)self->pPrivate;
if(priv->isRunning == 1){
SCWrite(pCon,"ERROR: cannot move while running",eError);
return 0;
}
if(nPar < 2){
SCWrite(pCon,"ERROR: internal: not enough parameters to Move",eError);
return 1;
}
if(par[1]->value.v.intValue == par[0]->value.v.intValue + 1){
/*
* already in right sequence, nothing to do
*/
return 1;
}
snprintf(name,80,"queue/%3.3d", par[1]->value.v.intValue);
moveNode = GetHipadabaNode(self->objectNode,name);
snprintf(name,80,"queue/%3.3d", par[0]->value.v.intValue);
insertNode = GetHipadabaNode(self->objectNode,name);
if(moveNode == NULL || insertNode == NULL){
SCWrite(pCon,"ERROR: move not possible, participating nodes not found",
eError);
return 0;
}
queueNode = GetHipadabaNode(self->objectNode,"queue");
if(moveNode == queueNode->child){
queueNode->child = queueNode->child->next;
moveNode->next = insertNode->next;
insertNode->next = moveNode;
} else {
prevNode = queueNode->child;
while(prevNode != NULL && prevNode->next != moveNode){
prevNode = prevNode->next;
}
if(insertNode == queueNode->child ){
/*
* insert at top
*/
tmp = queueNode->child;
queueNode->child = moveNode;
prevNode->next = moveNode->next;
moveNode->next = tmp;
} else {
tmp = insertNode->next;
insertNode->next = moveNode;
prevNode->next = moveNode->next;
moveNode->next = tmp;
}
}
sequentialNames(self->objectNode, pCon);
return 1;
}
/*---------------------------------------------------------------------------*/
static void Configure(pSICSOBJ self){
pHdb n = NULL, par = NULL;
hdbValue intValue, textValue, funcValue;
pHdb obj = self->objectNode;
intValue = MakeHdbInt(0);
textValue = MakeHdbText("Undefined");
n = MakeHipadabaNode("control",HIPNONE,1);
AddHipadabaChild(obj,n,NULL);
AddSICSHdbPar(n,"maxEntry",usInternal,intValue);
AddSICSHdbPar(n,"currentEntry",usInternal,intValue);
n = MakeHipadabaNode("queue",HIPNONE,1);
AddHipadabaChild(obj,n, NULL);
funcValue = MakeSICSFunc(EnqueFunc);
n = MakeSICSHdbPar("enqueue",usUser, funcValue);
AddSICSHdbPar(n,"description",usUser,textValue);
AddHipadabaChild(obj,n,NULL);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(AddCmdData);
n = MakeSICSHdbPar("addcommand",usUser, funcValue);
AddSICSHdbPar(n,"command",usUser,textValue);
AddHipadabaChild(obj,n,NULL);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(Dequeue);
n = MakeSICSHdbPar("dequeue",usUser,funcValue);
AddHipadabaChild(obj,n,NULL);
AddSICSHdbPar(n,"index",usUser,intValue);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(Clean);
n = MakeSICSHdbPar("clean",usUser, funcValue);
AddHipadabaChild(obj,n,NULL);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(CleanAll);
n = MakeSICSHdbPar("cleanall",usUser, funcValue);
AddHipadabaChild(obj,n,NULL);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(Start);
n = MakeSICSHdbPar("start",usUser, funcValue);
AddHipadabaChild(obj,n,NULL);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(Restart);
n = MakeSICSHdbPar("restart",usUser, funcValue);
AddHipadabaChild(obj,n,NULL);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(Stop);
n = MakeSICSHdbPar("stop",usUser, funcValue);
AddHipadabaChild(obj,n,NULL);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(Move);
n = MakeSICSHdbPar("move",usUser,funcValue);
AddHipadabaChild(obj,n,NULL);
AddSICSHdbPar(n,"moveindex",usUser,intValue);
AddSICSHdbPar(n,"insertindex",usUser,intValue);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
}
/*---------------------------------------------------------------------------*/
int MakeHDBQueue(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pSICSOBJ self = NULL;
pHdbQueue priv = NULL;
priv = (pHdbQueue)malloc(sizeof(HdbQueue));
self = SetupSICSOBJ(pCon,pSics, pData,argc, argv);
if(self == NULL || priv == NULL){
return 0;
}
Configure(self);
memset(priv,0,sizeof(HdbQueue));
self->pPrivate = priv;
self->KillPrivate = free;
return 1;
}

15
hdbqueue.h Normal file
View File

@ -0,0 +1,15 @@
/**
* This is the new Hipadab based queuing system in support of the MountainGum
* user interface.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, July 2007
*/
#ifndef HDBQUEUE_H_
#define HDBQUEUE_H_
int MakeHDBQueue(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
#endif /*HDBQUEUE_H_*/

View File

@ -14,11 +14,64 @@
#define ABS(x) (x < 0 ? -(x) : (x))
#define HDBMAGICK 77119900
/*================== Message Stuff ========================================*/
static char set[] = {"set"};
static char get[] = {"get"};
static char update[] = {"update"};
static char treeChange[] = {"treeChange"};
static char dataSearch[] = {"dataSearch"};
static char killNode[] = {"killNode"};
/*------------------------------------------------------------------------*/
pHdbDataMessage GetHdbSetMessage(pHdbMessage toTest){
if(toTest->type == set){
return (pHdbDataMessage)toTest;
}
return NULL;
}
/*------------------------------------------------------------------------*/
pHdbDataMessage GetHdbGetMessage(pHdbMessage toTest){
if(toTest->type == get){
return (pHdbDataMessage)toTest;
}
return NULL;
}
/*------------------------------------------------------------------------*/
pHdbDataMessage GetHdbUpdateMessage(pHdbMessage toTest){
if(toTest->type == update){
return (pHdbDataMessage)toTest;
}
return NULL;
}
/*-------------------------------------------------------------------------*/
pHdbTreeChangeMessage GetHdbTreeChangeMessage(pHdbMessage toTest){
if(toTest->type == treeChange){
return (pHdbTreeChangeMessage)toTest;
}
return NULL;
}
/*-------------------------------------------------------------------------*/
pHdbDataSearch GetHdbDataSearchMessage(pHdbMessage toTest){
if(toTest->type == dataSearch){
return (pHdbDataSearch)toTest;
}
return NULL;
}
/*-------------------------------------------------------------------------*/
pHdbMessage GetHdbKillNodeMessage(pHdbMessage toTest){
if(toTest->type == killNode){
return toTest;
}
return NULL;
}
/*================== internal functions ===================================*/
void DeleteCallbackChain(pHdbCallback root){
void DeleteCallbackChain(pHdb node){
pHdbCallback current = NULL, thisEntry;
hdbMessage killNodeMsg;
current = root;
killNodeMsg.type = killNode;
InvokeCallbackChain(node, &killNodeMsg);
current = node->callBackChain;
while(current != NULL){
if(current->killFunc != NULL){
current->killFunc(current->userData);
@ -28,17 +81,26 @@ void DeleteCallbackChain(pHdbCallback root){
free(thisEntry);
}
}
/*----------------------------------------------------------------------*/
void RecurseCallbackChains(pHdb node, pHdbMessage message){
pHdb current = NULL;
InvokeCallbackChain(node,message);
current = node->child;
while(current != NULL){
RecurseCallbackChains(current,message);
current = current->next;
}
}
/*-----------------------------------------------------------------------*/
static void DeleteNodeData(pHdb node){
void DeleteNodeData(pHdb node){
pHdb tmp = NULL;
if(node == NULL){
return;
}
DeleteCallbackChain(node->writeCallbacks);
DeleteCallbackChain(node->updateCallbacks);
DeleteCallbackChain(node->readCallbacks);
DeleteCallbackChain(node->treeChangeCallbacks);
DeleteCallbackChain(node);
if(node->properties != NULL){
DeleteStringDict(node->properties);
}
@ -59,145 +121,102 @@ static void DeleteNodeData(pHdb node){
}
free(node);
}
/*-------------------------------------------------------------------------*/
static int InvokeCallbackChain(pHdbCallback root, pHdb node,
void *callData, hdbValue v){
pHdbCallback current = root;
int status;
/*------------------------------------------------------------------------*/
static pHdbCallback CleanCallbackChain(pHdbCallback head){
pHdbCallback current = head;
pHdbCallback next;
pHdbCallback *ptr2last = &head;
while(current != NULL){
status = current->userCallback(current->userData,callData,
node,v);
if(status != 1){
return status;
if(current->killFlag == 1){
next = current->next;
/*
* unlink
*/
*ptr2last = next;
/*
* delete
*/
if(current->killFunc != NULL){
current->killFunc(current->userData);
}
free(current);
/*
* move on
*/
current = next;
} else {
ptr2last = &current->next;
current = current->next;
}
}
return head;
}
/*-------------------------------------------------------------------------*/
int InvokeCallbackChain(pHdb node, pHdbMessage message){
pHdbCallback current = node->callBackChain;
hdbCallbackReturn status;
int killFlag = 0;
while(current != NULL){
status = current->userCallback(node, current->userData,message);
switch(status){
case hdbAbort:
return 0;
break;
case hdbKill:
current->killFlag = 1;
killFlag = 1;
break;
case hdbContinue:
break;
}
current = current->next;
}
if(killFlag == 1){
node->callBackChain = CleanCallbackChain(node->callBackChain);
}
return 1;
}
/*-----------------------------------------------------------------------*/
static void SendTreeChangeMessage(pHdb node, void *callData){
hdbTreeChangeMessage treeChangeMes;
treeChangeMes.type = treeChange;
treeChangeMes.callData = callData;
InvokeCallbackChain(node, (pHdbMessage)&treeChangeMes);
}
/*------------------------------------------------------------------------*/
void RemoveHdbNodeFromParent(pHdb node, void *callData){
pHdb parent = NULL;
pHdb current = NULL;
hdbTreeChangeMessage treeChangeMes;
parent = node->mama;
if(parent != NULL){
if(parent->child == node){
parent->child = node->next;
return;
}
} else {
current = parent->child;
while(current->next != node){
current = current->next;
}
current->next = current->next->next;
InvokeCallbackChain(parent->treeChangeCallbacks,
parent,callData,parent->value);
}
SendTreeChangeMessage(parent,callData);
node->mama = NULL;
}
}
/*-----------------------------------------------------------------------*/
static void RemoveCallbackNode(pHdbCallback victim){
if(victim->previous != NULL) {
victim->previous->next = victim->next;
}
if(victim->next != NULL){
victim->next->previous = victim->previous;
}
if(victim->killFunc != NULL){
victim->killFunc(victim->userData);
}
free(victim);
}
/*-----------------------------------------------------------------------
* This code is ugly: the problem is fixing up the start of the chain.
* Think about it and improve
* ----------------------------------------------------------------------*/
static pHdbCallback DeleteForID(pHdbCallback root, int id){
pHdbCallback current = root;
pHdbCallback tmp = NULL;
pHdbCallback result = NULL;
if(root == NULL){
return NULL;
}
/*
* delete at the start of the chain
*/
result = root;
while(result->id == id){
tmp = result;
result = result->next;
RemoveCallbackNode(tmp);
if(result == NULL){
return NULL;
}
}
/*
* delete nodes in the middle of the chain
*/
current = result;
/*----------------------------------------------------------------------*/
int CountHdbChildren(pHdb node){
int count = 0;
pHdb current = NULL;
current = node->child;
while(current != NULL){
if(current->id == id){
tmp = current;
current = (pHdbCallback)current->next;
RemoveCallbackNode(tmp);
} else {
current = (pHdbCallback)current->next;
current = current->next;
count++;
}
}
return result;
}
/*-----------------------------------------------------------------------*/
static pHdbCallback DeleteForInternalID(pHdbCallback root, int id){
pHdbCallback current = root;
pHdbCallback tmp = NULL;
pHdbCallback result = NULL;
if(root == NULL){
return NULL;
}
/*
* delete at the start of the chain
*/
result = root;
while(result->internalID == id){
tmp = result;
result = result->next;
if(tmp->killFunc != NULL){
tmp->killFunc(tmp->userData);
}
free(tmp);
if(result == NULL){
return NULL;
}
}
/*
* delete nodes in the middle of the chain
*/
current = result;
while(current != NULL){
if(current->internalID == id){
if(current->next != NULL){
current->next->previous = current->previous;
}
if(current->previous != NULL){
current->previous->next = current->next;
}
tmp = current;
current = (pHdbCallback)current->next;
if(tmp->killFunc != NULL){
tmp->killFunc(tmp->userData);
}
free(tmp);
} else {
current = (pHdbCallback)current->next;
}
}
return result;
return count;
}
/*----------------------------------------------------------------------*/
char *hdbTrim(char *str)
@ -274,6 +293,7 @@ hdbValue makeHdbValue(int datatype, int length){
memset(&val,0,sizeof(hdbValue));
val.dataType = datatype;
val.doNotFree = 0;
switch(datatype){
case HIPINTAR:
@ -299,60 +319,6 @@ hdbValue makeHdbValue(int datatype, int length){
}
return val;
}
/*------------------------------------------------------------------------*/
hdbValue makeHdbData(int datatype, int length, void *data){
hdbValue val;
memset(&val,0,sizeof(hdbValue));
val.dataType = datatype;
switch(datatype){
case HIPINT:
if(data != NULL){
memcpy(&val.v.intValue,data,sizeof(int));
}
break;
case HIPFLOAT:
if(data != NULL){
memcpy(&val.v.doubleValue,data,sizeof(double));
}
break;
case HIPINTAR:
case HIPINTVARAR:
val.arrayLength = length;
val.v.intArray = malloc(length*sizeof(int));
if(val.v.intArray != NULL){
memset(val.v.intArray,0,length*sizeof(int));
}
if(data != NULL){
memcpy(val.v.intArray,data,length*sizeof(int));
}
break;
case HIPFLOATAR:
case HIPFLOATVARAR:
val.arrayLength = length;
val.v.floatArray = malloc(length*sizeof(double));
if(val.v.floatArray != NULL){
memset(val.v.floatArray,0,length*sizeof(double));
}
if(data != NULL){
memcpy(val.v.floatArray,data,length*sizeof(double));
}
break;
case HIPTEXT:
if(data != NULL){
val.v.text = strdup((char *)data);
} else {
val.v.text = strdup("UNKNOWN");
}
val.arrayLength = strlen(val.v.text);
break;
case HIPOBJ:
val.v.obj = data;
break;
}
return val;
}
/*-------------------------------------------------------------------------*/
hdbValue MakeHdbInt(int initValue){
hdbValue result;
@ -376,7 +342,7 @@ hdbValue MakeHdbText(char *initText){
hdbValue result;
result.dataType = HIPTEXT;
result.v.text = initText;
result.v.text = initText; /* no strdup here ! */
result.arrayLength = strlen(initText);
return result;
}
@ -390,7 +356,7 @@ hdbValue MakeHdbIntArray(int length, int *data){
return result;
}
/*-------------------------------------------------------------------------*/
hdbValue MakeHdbFloatArrray(int length, double *data){
hdbValue MakeHdbFloatArray(int length, double *data){
hdbValue result;
result.dataType = HIPFLOATAR;
@ -399,7 +365,27 @@ hdbValue MakeHdbFloatArrray(int length, double *data){
return result;
}
/*-------------------------------------------------------------------------*/
hdbValue MakeHdbFunc(voidFunc *func){
hdbValue result;
result.dataType = HIPFUNC;
result.v.func = func;
return result;
}
/*-------------------------------------------------------------------------*/
hdbValue MakeHdbObj(void *obj){
hdbValue result;
result.dataType = HIPOBJ;
result.v.obj = obj;
return result;
}
/*-------------------------------------------------------------------------*/
void ReleaseHdbValue(hdbValue *v){
if(v->doNotFree == 1){
return;
}
switch(v->dataType){
case HIPTEXT:
if(v->v.text != NULL){
@ -447,6 +433,9 @@ int compareHdbValue(hdbValue v1, hdbValue v2){
}
break;
case HIPTEXT:
if(v1.v.text == NULL || v2.v.text == NULL){
return 0;
}
if(strcmp(v1.v.text,v2.v.text) == 0){
return 1;
} else {
@ -458,6 +447,9 @@ int compareHdbValue(hdbValue v1, hdbValue v2){
if(v1.arrayLength != v2.arrayLength){
return 0;
}
if(v1.v.intArray == NULL || v2.v.intArray == NULL){
return 0;
}
for(i = 0; i < v1.arrayLength; i++){
if(v1.v.intArray[i] != v2.v.intArray[i]){
return 0;
@ -470,6 +462,9 @@ int compareHdbValue(hdbValue v1, hdbValue v2){
if(v1.arrayLength != v2.arrayLength){
return 0;
}
if(v1.v.floatArray == NULL || v2.v.floatArray == NULL){
return 0;
}
for(i = 0; i < v1.arrayLength; i++){
if(ABS(v1.v.floatArray[i] - v2.v.floatArray[i]) > .01){
return 0;
@ -484,6 +479,13 @@ int compareHdbValue(hdbValue v1, hdbValue v2){
return 0;
}
break;
case HIPFUNC:
if(v2.v.func == v1.v.func) {
return 1;
} else {
return 0;
}
break;
default:
assert(0);
break;
@ -494,6 +496,7 @@ int compareHdbValue(hdbValue v1, hdbValue v2){
int cloneHdbValue(hdbValue *source, hdbValue *clone){
memset(clone,0,sizeof(hdbValue));
clone->v.text = NULL; /* this sets all pointers in the union to NULL */
clone->dataType = source->dataType;
return copyHdbValue(source, clone);
}
@ -523,6 +526,9 @@ int getHdbValueLength(hdbValue v){
case HIPOBJ:
length = sizeof(void *);
break;
case HIPFUNC:
length = sizeof(voidFunc *);
break;
}
return length;
}
@ -594,8 +600,7 @@ void AddHipadabaChild(pHdb parent, pHdb child, void *callData){
child->next = NULL;
prev->next = child;
}
InvokeCallbackChain(parent->treeChangeCallbacks,
parent,callData,parent->value);
SendTreeChangeMessage(parent,callData);
}
/*--------------------------------------------------------------------------*/
void DeleteHipadabaNode(pHdb node, void *callData){
@ -705,8 +710,7 @@ char *GetHipadabaPath(pHdb node){
}
/*==================== Callback Functions ==================================*/
pHdbCallback MakeHipadabaCallback(hdbCallbackFunction func,
void *userData, killUserData killFunc,
int id, int internalID){
void *userData, killUserData killFunc){
pHdbCallback pNew = NULL;
assert(func != NULL);
@ -720,142 +724,68 @@ pHdbCallback MakeHipadabaCallback(hdbCallbackFunction func,
pNew->userCallback = func;
pNew->userData = userData;
pNew->killFunc = killFunc;
pNew->id = id;
pNew->internalID = internalID;
return pNew;
}
/*-------------------------------------------------------------------*/
void AppendHipadabaCallback(pHdb node, int type, pHdbCallback newCB){
void AppendHipadabaCallback(pHdb node, pHdbCallback newCB){
pHdbCallback current = NULL;
switch(type){
case HCBSET:
if(node->writeCallbacks == NULL){
node->writeCallbacks = newCB;
assert(node);
current = node->callBackChain;
newCB->next = NULL;
if(current == NULL){
node->callBackChain = newCB;
return;
} else {
current = node->writeCallbacks;
}
break;
case HCBUPDATE:
if(node->updateCallbacks == NULL){
node->updateCallbacks = newCB;
return;
} else {
current = node->updateCallbacks;
}
break;
case HCBREAD:
if(node->readCallbacks == NULL){
node->readCallbacks = newCB;
return;
} else {
current = node->readCallbacks;
}
break;
case HCBTREE:
if(node->treeChangeCallbacks == NULL){
node->treeChangeCallbacks = newCB;
return;
} else {
current = node->treeChangeCallbacks;
}
break;
default:
assert(0);
break;
}
if(current != NULL){
while(current->next != NULL){
current = (pHdbCallback)current->next;
}
current->next= newCB;
newCB->previous = current;
}
current->next = newCB;
}
/*---------------------------------------------------------------------------*/
void PrependHipadabaCallback(pHdb node, int type, pHdbCallback newCB){
switch(type){
case HCBSET:
if(node->writeCallbacks == NULL){
node->writeCallbacks = newCB;
return;
} else {
newCB->next = node->writeCallbacks;
node->writeCallbacks->previous = newCB;
node->writeCallbacks = newCB;
}
break;
case HCBUPDATE:
if(node->updateCallbacks == NULL){
node->updateCallbacks = newCB;
return;
} else {
newCB->next = node->updateCallbacks;
node->updateCallbacks->previous = newCB;
node->updateCallbacks = newCB;
}
break;
case HCBREAD:
if(node->readCallbacks == NULL){
node->readCallbacks = newCB;
return;
} else {
newCB->next = node->readCallbacks;
node->readCallbacks->previous = newCB;
node->readCallbacks = newCB;
}
break;
case HCBTREE:
if(node->treeChangeCallbacks == NULL){
node->treeChangeCallbacks = newCB;
return;
} else {
newCB->next = node->treeChangeCallbacks;
node->treeChangeCallbacks->previous = newCB;
node->treeChangeCallbacks = newCB;
}
break;
default:
assert(0);
break;
}
void PrependHipadabaCallback(pHdb node,pHdbCallback newCB){
assert(node != NULL);
newCB->next = node->callBackChain;
node->callBackChain = newCB;
}
/*----------------------------------------------------------------------------*/
void RemoveHipadabaCallback(pHdb root, int id){
pHdb current = NULL;
void *FindHdbCallbackData(pHdb node, void *userPtr){
hdbDataSearch dsm;
root->writeCallbacks = DeleteForID(root->writeCallbacks,id);
root->updateCallbacks = DeleteForID(root->updateCallbacks,id);
root->readCallbacks = DeleteForID(root->readCallbacks,id);
root->treeChangeCallbacks = DeleteForID(root->treeChangeCallbacks,id);
dsm.type = dataSearch;
dsm.testPtr = userPtr;
dsm.result = NULL;
current = root->child;
while(current != NULL){
RemoveHipadabaCallback(current,id);
current = current->next;
}
}
/*----------------------------------------------------------------------------*/
void InternalRemoveHipadabaCallback(pHdb root, int internalID){
pHdb current = NULL;
InvokeCallbackChain(node, (pHdbMessage)&dsm);
return dsm.result;
root->writeCallbacks = DeleteForInternalID(root->writeCallbacks,internalID);
root->updateCallbacks = DeleteForInternalID(root->updateCallbacks,internalID);
root->readCallbacks = DeleteForInternalID(root->readCallbacks,internalID);
root->treeChangeCallbacks = DeleteForInternalID(root->treeChangeCallbacks,internalID);
current = root->child;
while(current != NULL){
InternalRemoveHipadabaCallback(current,internalID);
current = current->next;
}
}
/*=================== parameter interface ====================================*/
static int canCopy(hdbValue *source, hdbValue *target){
if(target->dataType == HIPINTVARAR) {
if(source->dataType == HIPINTAR ||
source->dataType == HIPINTVARAR){
return 1;
}
}
if(target->dataType == HIPFLOATVARAR) {
if(source->dataType == HIPFLOATAR ||
source->dataType == HIPFLOATVARAR){
return 1;
}
}
if(source->dataType != target->dataType){
return 0;
} else {
return 1;
}
}
/*----------------------------------------------------------------------------*/
int copyHdbValue(hdbValue *source, hdbValue *target){
int i;
if(source->dataType != target->dataType){
if(!canCopy(source,target)){
return 0;
}
@ -884,7 +814,8 @@ int copyHdbValue(hdbValue *source, hdbValue *target){
if(target->v.intArray == NULL){
return 0;
}
memset(target->v.intArray,0,source->arrayLength * sizeof(int));
memset(target->v.intArray,0,source->arrayLength
* sizeof(int));
target->arrayLength = source->arrayLength;
}
if(source->v.intArray != NULL){
@ -895,15 +826,18 @@ int copyHdbValue(hdbValue *source, hdbValue *target){
break;
case HIPFLOATAR:
case HIPFLOATVARAR:
if(target->arrayLength != source->arrayLength || target->v.floatArray == NULL){
if(target->arrayLength != source->arrayLength
|| target->v.floatArray == NULL){
if(target->v.floatArray != NULL){
free(target->v.floatArray);
}
target->v.floatArray = malloc(source->arrayLength * sizeof(double));
target->v.floatArray =
malloc(source->arrayLength * sizeof(double));
if(target->v.floatArray == NULL){
return 0;
}
memset(target->v.floatArray,0,source->arrayLength * sizeof(double));
memset(target->v.floatArray,0,source->arrayLength *
sizeof(double));
target->arrayLength = source->arrayLength;
}
if(source->v.floatArray != NULL){
@ -915,6 +849,9 @@ int copyHdbValue(hdbValue *source, hdbValue *target){
case HIPOBJ:
target->v.obj = source->v.obj;
break;
case HIPFUNC:
target->v.func = source->v.func;
break;
default:
/*
* unknown data type
@ -924,33 +861,48 @@ int copyHdbValue(hdbValue *source, hdbValue *target){
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int SendDataMessage(pHdb node, char *type,
hdbValue v, void *callData){
hdbDataMessage dataMes;
assert(type == set || type == get || type == update);
dataMes.type = type;
dataMes.v = &v;
dataMes.callData = callData;
return InvokeCallbackChain(node, (pHdbMessage)&dataMes);
}
/*----------------------------------------------------------------------------*/
int SetHipadabaPar(pHdb node, hdbValue v, void *callData){
int status;
status = InvokeCallbackChain(node->writeCallbacks, node, callData, v);
return status;
return SendDataMessage(node, set, v,callData);
}
/*-----------------------------------------------------------------------------*/
int UpdateHipadabaPar(pHdb node, hdbValue v, void *callData){
int status;
status = InvokeCallbackChain(node->updateCallbacks, node, callData, v);
if(status != 1 ){
return status;
}
status = SendDataMessage(node, update, v,callData);
if(status == 1){
copyHdbValue(&v,&node->value);
}
return status;
}
/*-----------------------------------------------------------------------------*/
int NotifyHipadabaPar(pHdb node,void *callData){
SendDataMessage(node, update, node->value,callData);
return 1;
}
/*-----------------------------------------------------------------------------*/
int GetHipadabaPar(pHdb node, hdbValue *v, void *callData){
int status;
status = InvokeCallbackChain(node->readCallbacks, node, callData, *v);
v->dataType = node->value.dataType;
v->doNotFree = 0;
v->v.text = NULL; /* this sets all pointers in the union to NULL */
status = SendDataMessage(node, get, *v,callData);
if(status != 1 ){
return status;
}
v->dataType = node->value.dataType;
copyHdbValue(&node->value,v);
return 1;
}
@ -966,112 +918,12 @@ static int calcDataLength(pHdb node, int testLength){
}
return length;
}
/*--------------------------------------------------------------------------*/
int SetHdbPar(pHdb node, int dataType, void *data, int length,
void *callData){
int status;
hdbValue v;
if(node->value.dataType == HIPNONE){
return 1;
}
if(dataType != node->value.dataType){
return HDBTYPEMISMATCH;
}
if(length != calcDataLength(node,length)){
return HDBLENGTHMISMATCH;
}
v = makeHdbData(dataType, length, data);
status = InvokeCallbackChain(node->writeCallbacks, node, callData, v);
if(status == 1) {
copyHdbValue(&v,&node->value);
}
return status;
}
/*--------------------------------------------------------------------------*/
int UpdateHdbPar(pHdb node, int dataType, void *data, int length,
void *callData){
int status;
hdbValue v;
if(node->value.dataType == HIPNONE){
return 1;
}
if(dataType != node->value.dataType){
return HDBTYPEMISMATCH;
}
if(length != calcDataLength(node,length)){
return HDBLENGTHMISMATCH;
}
v = makeHdbData(dataType,length,data);
status = InvokeCallbackChain(node->updateCallbacks, node, callData, v);
if(status == 1) {
copyHdbValue(&v,&node->value);
}
return status;
}
/*-----------------------------------------------------------------------------*/
int GetHdbPar(pHdb node, int dataType, void *data, int length,
void *callData){
int status, toCopy;
hdbValue v;
if(dataType != node->value.dataType){
return HDBTYPEMISMATCH;
}
if(length != calcDataLength(node,length)){
return HDBLENGTHMISMATCH;
}
status = InvokeCallbackChain(node->readCallbacks, node, callData, v);
if(status != 1 ){
return status;
}
switch(dataType){
case HIPNONE:
break;
case HIPINT:
memcpy(data,&node->value.v.intValue,sizeof(int));
break;
case HIPFLOAT:
memcpy(data,&node->value.v.doubleValue,sizeof(double));
break;
case HIPINTAR:
case HIPINTVARAR:
memcpy(data,node->value.v.intArray,
node->value.arrayLength*sizeof(int));
break;
case HIPTEXT:
toCopy = strlen(node->value.v.text);
if(toCopy > length){
toCopy = length;
}
memcpy(data,&node->value.v.text, toCopy);
break;
case HIPFLOATAR:
case HIPFLOATVARAR:
memcpy(data,node->value.v.floatArray,
node->value.arrayLength*sizeof(double));
break;
case HIPOBJ:
memcpy(data,&node->value.v.obj,sizeof(void *));
break;
default:
assert(0);
break;
}
return 1;
}
/*============================= Property Functions ==========================*/
void SetHdbProperty(pHdb node, char *key, char *value){
if(node != NULL && key != NULL && node->properties != NULL){
if(StringDictExists(node->properties, key)){
if (value == NULL) {
StringDictDelete(node->properties, key);
} else if(StringDictExists(node->properties, key)){
StringDictUpdate(node->properties,key,value);
} else {
StringDictAddPair(node->properties,key,value);
@ -1087,6 +939,14 @@ int GetHdbProperty(pHdb node, char *key, char *value, int len){
}
}
/*---------------------------------------------------------------------------*/
char *GetHdbProp(pHdb node, char *key){
if(node != NULL && node->properties != NULL){
return StringDictGetShort(node->properties,key);
} else {
return NULL;
}
}
/*---------------------------------------------------------------------------*/
void InitHdbPropertySearch(pHdb node){
if(node != NULL && node->properties != NULL){
StringDictKillScan(node->properties);

View File

@ -1,4 +1,4 @@
/**
/** @file
* Hipadaba is a hierarchical database of parameters. Parameters can be of
* various types. What happens when a parameter is being set, updated or read
* is largely determined through callbacks which can be registered on
@ -24,6 +24,8 @@
* Added treeChange callback, Mark Koennecke, November 2006
*
* Added support for properties, Mark Koennecke, January 2007
*
* Refactored callback handling, Markus Zolliker, Mark Koennecke, March 2008
*/
#ifndef HIPADABA
#define HIPADABA
@ -39,24 +41,24 @@
#define HIPINTVARAR 5
#define HIPFLOATVARAR 6
#define HIPOBJ 7
/* -------- callback types */
#define HCBSET 0
#define HCBUPDATE 1
#define HCBREAD 2
#define HCBTREE 3
#define HIPFUNC 8
/*--------- error codes */
#define HDBTYPEMISMATCH -7701
#define HDBLENGTHMISMATCH -7702
/*===================== structure definitions ===================================*/
typedef void voidFunc(void);
typedef struct __hdbValue {
int dataType;
int arrayLength;
int doNotFree;
union __value {
int intValue;
double doubleValue;
char *text;
int *intArray;
double *floatArray;
voidFunc *func;
void *obj;
}v;
}hdbValue;
@ -66,41 +68,103 @@ typedef struct __hipadaba {
struct __hipadaba *mama;
struct __hipadaba *child;
struct __hipadaba *next;
struct __hdbcallback *writeCallbacks;
struct __hdbcallback *updateCallbacks;
struct __hdbcallback *readCallbacks;
struct __hdbcallback *treeChangeCallbacks;
struct __hdbcallback *callBackChain;
char *name;
char *path;
hdbValue value;
int protected;
pStringDict properties;
}Hdb, *pHdb;
/*-------------- return values for callback functions -------------------------*/
typedef enum {hdbContinue,
hdbAbort,
hdbKill } hdbCallbackReturn;
/*======================== Messages ===========================================*/
typedef struct __hdbMessage {
char *type;
} hdbMessage, *pHdbMessage;
/*-----------------------------------------------------------------------------*/
typedef struct {
char *type;
hdbValue *v;
void *callData;
}hdbDataMessage, *pHdbDataMessage;
/*-------------------------------------------------------------------------------*/
typedef int (*hdbCallbackFunction)(void *userData, void *callData,
pHdb currentNode, hdbValue v);
typedef struct {
char *type;
void *callData;
}hdbTreeChangeMessage, *pHdbTreeChangeMessage;
/*-------------------------------------------------------------------------------*/
typedef struct {
char *type;
void *testPtr;
void *result;
}hdbDataSearch, *pHdbDataSearch;
/*-------------------------------------------------------------------------------*/
typedef hdbCallbackReturn (*hdbCallbackFunction)(pHdb currentNode,
void *userData,
pHdbMessage message);
typedef void (*killUserData)(void *data);
/*-------------------------------------------------------------------------------*/
typedef struct __hdbcallback {
void *userData;
killUserData killFunc;
hdbCallbackFunction userCallback;
int id;
int internalID;
int killFlag;
struct __hdbcallback *next;
struct __hdbcallback *previous;
}hdbCallback, *pHdbCallback;
/*======================== Function protoypes: hdbData ========================*/
hdbValue makeHdbValue(int datatype, int length);
/*============= Message Test Functions ==========================================*/
/**
* make a hdbValue and initailize it with the data in the void
* pointer. Do not initialise when data = NULL.
* @param dataType The datatype of the hdbValue
* @param The array length of the hdbValue
* @param data Initialisation data for hdbValue
* Test a message if it is a set message
* @param toTest The message to test.
* @return NULL if the message is no set message or a message pointer if it is.
*/
pHdbDataMessage GetHdbSetMessage(pHdbMessage toTest);
/**
* Test a message if it is a set message
* @param toTest The message to test.
* @return NULL if the message is no set message or a message pointer if it is.
*/
pHdbDataMessage GetHdbGetMessage(pHdbMessage toTest);
/**
* Test a message if it is a update message
* @param toTest The message to test.
* @return NULL if the message is no update message or a message pointer if
* it is.
*/
pHdbDataMessage GetHdbUpdateMessage(pHdbMessage toTest);
/**
* Test a message if it is a tree change message
* @param toTest The message to test.
* @return NULL if the message is no tree change message or a message
* pointer if it is.
*/
pHdbTreeChangeMessage GetHdbTreeChangeMessage(pHdbMessage toTest);
/**
* Test a message if it is a data search message
* @param toTest The message to test.
* @return NULL if the message is no data search message or a message
* pointer if it is.
*/
pHdbDataSearch GetHdbDataSearchMessage(pHdbMessage toTest);
/**
* Test a message if it is a kill node message
* @param toTest The message to test.
* @return NULL if the message is no kill node message or a message
* pointer if it is.
*/
pHdbMessage GetHdbKillNodeMessage(pHdbMessage toTest);
/*======================== Function protoypes: hdbData ========================*/
/**
* make a hdbValue with the given datatype and length
* Do not initialise
* @param datatype The datatype of the hdbValue
* @param length The array length of the hdbValue
* @return a suitably defined hdbValue
*/
hdbValue makeHdbData(int datatype, int length, void *data);
hdbValue makeHdbValue(int datatype, int length);
/**
* wrap an integer as an hdbValue
* @param initValue the initial value of the int
@ -142,6 +206,18 @@ hdbValue MakeHdbIntArray(int length, int *data);
* @return: A properly initialized hdbValue structure
*/
hdbValue MakeHdbFloatArray(int length, double *data);
/**
* wrap a function as an hdbValue
* @param func the function
* @return: A properly initialized hdbValue structure
*/
hdbValue MakeHdbFunc(voidFunc *func);
/**
* wrap an object as an hdbValue
* @param obj the object
* @return: A properly initialized hdbValue structure
*/
hdbValue MakeHdbObj(void *obj);
/**
* release any dynamic memory associated with v
* @param v The hdbValue to check for dynamic memory allocation to be
@ -182,6 +258,7 @@ int getHdbValueLength(hdbValue v);
* make a new hipadaba node
* @param name The name of the new node
* @param datatype The datatype of the new node
* @param length the array length
* @return a new node or NULL when out of memory
*/
pHdb MakeHipadabaNode(char *name, int datatype, int length);
@ -193,8 +270,14 @@ pHdb MakeHipadabaNode(char *name, int datatype, int length);
*/
void AddHipadabaChild(pHdb parent, pHdb child, void *callData);
/**
* delete a hipadaba node and all its children
* @parma node The node to delete
* Delete only the node data, without invoking any callbacks
* @param node The node to delete.
*/
void DeleteNodeData(pHdb node);
/**
* delete a hipadaba node and all its children. Then invoke the tree
* change callback to notify listeners.
* @param node The node to delete
* @param callData User data for the tree change callback
*/
void DeleteHipadabaNode(pHdb node, void *callData);
@ -220,15 +303,16 @@ pHdb GetHipadabaNode(pHdb root, char *path);
char *GetHipadabaPath(pHdb node);
/**
* removes a node from the parents child list.
* @node the node to remove
* @param node the node to remove
* @param callData User data for the tree change callback
*/
void RemoveHdbNodeFromParent(pHdb node, void *callData);
/**
* delete a callback chain
* @param root The callback chain to delete
* count the numbers of children in thie Hdb node
* @param node The node to count children for
* @return The number of children
*/
void DeleteCallbackChain(pHdbCallback root);
int CountHdbChildren(pHdb node);
/*===================== function protoypes: Callbacks ========================*/
/**
* make a new hipdaba callback
@ -236,42 +320,50 @@ void DeleteCallbackChain(pHdbCallback root);
* @param userData userData to be associated with this callback. Can be NULL.
* @param killFunc A function for freeing the userData. Can be NULL, then it will
* not be invoked
* @param id An ID associated with this callback
* @param internalID Another ID to be associated with this callback. ID's come in
* useful when callbacks have to be deleted in a later stage.
* @return A new suitabvly initialised callback structure or NULL when required elements
* @return A new suitabaly initialised callback structure or NULL when required elements
* are missing or there is nor memory.
*/
pHdbCallback MakeHipadabaCallback(hdbCallbackFunction func,
void *userData, killUserData killFunc,
int id, int internalID);
void *userData, killUserData killFunc);
/**
* add a callback at the end of the callback chain
* @param node The node to which to append the callback
* @param type the type of the callback to append
* @param newCB The callback to append
*/
void AppendHipadabaCallback(pHdb node,int type, pHdbCallback newCB);
void AppendHipadabaCallback(pHdb node,pHdbCallback newCB);
/**
* add a callback at the head of the callback chain
* @param node The node to which to append the callback
* @param type the type of the callback to append
* @param newCB The callback prepend
*/
void PrependHipadabaCallback(pHdb node, int type, pHdbCallback newCB);
void PrependHipadabaCallback(pHdb node,pHdbCallback newCB);
/**
* remove recursively all callbacks witch match the id
* @param root The starting node from where to start removing callbacks
* @param id The ID callbacks have to match in order to be removed.
* find the callback data
* @param node the node from where callbacks have to be searched
* @param userPtr A pointer to some user data which the callback
* uses to determine if it is the right one.
* @return the found callback user data or NULL on failure
*/
void RemoveHipadabaCallback(pHdb root, int id);
void *FindHdbCallbackData(pHdb node, void *userPtr);
/**
* remove recursively all callbacks witch match the internal id
* @param root The starting node from where to start removing callbacks
* @param internalID The internal ID callbacks have to match in order to be removed.
* invoke a callback chain.
* @param node The node reponsible for this callback chain
* @param message the message to send
* @return 1 on success, 0 on failure
*/
void InternalRemoveHipadabaCallback(pHdb root, int internalID);
int InvokeCallbackChain(pHdb node, pHdbMessage message);
/**
* Deletes the callback chain of a node. This is internal, normal users
* should not use this function. Or you create a mess!
* @param node The node
*/
void DeleteCallbackChain(pHdb node);
/**
* apply message to the node and all its children
* @param node Th node where to start recursing
* @param message The message to send
*/
void RecurseCallbackChains(pHdb node, pHdbMessage message);
/*============== Parameter Handling ===============================*/
/**
* Set a hipadaba parameter. This is an external set for a parameter. It may cause
@ -291,6 +383,14 @@ int SetHipadabaPar(pHdb node, hdbValue v, void *callData);
* @return 0 on failure, 1 on success
*/
int UpdateHipadabaPar(pHdb node, hdbValue v, void *callData);
/**
* notify any update listeners that this node has been internally modifed.
* @param node The node modified
* @param callData Addtional data for the callback
* @return 1 on success, 0 on failure
*/
int NotifyHipadabaPar(pHdb node,void *callData);
/**
* Read a hipadaba parameter
* @param node The node for which to read the parameter
@ -299,42 +399,6 @@ int UpdateHipadabaPar(pHdb node, hdbValue v, void *callData);
* @return 0 on failure, 1 on success
*/
int GetHipadabaPar(pHdb node, hdbValue *v, void *callData);
/**
* Set a hipadaba parameter. This is an external set for a parameter. It may cause
* motors to start driving etc.
* @param node The node for which to set the parameter
* param dataType The datatype the value ought to have
* @param data A pointer to the data to set.
* @param length The length of data
* @param callData Additonal context data to be passed to the callback functions
* @return 0 on failure, a negative error code on failure
*/
int SetHdbPar(pHdb node, int dataType, void *data, int length,
void *callData);
/**
* Updates a hipadaba parameter. This does not cause an active parameter to
* start driving but invokes all notifications which may be registered on
* this parameter.
* @param node The node for which to set the parameter
* param dataType The datatype the value ought to have
* @param data A pointer to the data to set.
* @param length The length of data
* @param callData Additonal context data to be passed to the callback functions
* @return 0 on failure, a negative error code on failure
*/
int UpdateHdbPar(pHdb node, int dataType, void *data, int length,
void *callData);
/**
* Read a hipadaba parameter
* @param node The node for which to read the parameter
* @param dataType The expected type of the data
* @param data A pointer to which data will be copied
* @param length The length of data.
* @param callData Additonal context data to be passed to the callback functions
* @return 0 on failure, a negative error code on failures.
*/
int GetHdbPar(pHdb node, int dataType, void *data, int length,
void *callData);
/*================================ Property Interface ==============================================*/
/**
* set a property
@ -352,6 +416,14 @@ int GetHdbPar(pHdb node, int dataType, void *data, int length,
* @return 0 on failure, 1 on success
*/
int GetHdbProperty(pHdb node, char *key, char *value, int len);
/**
* get the value of a property
* @param node The node to get the property from
* @param key The properties key
* @return the property or NULL on failure. Warning: the string is
* only valid as long as the property has not changed
*/
char *GetHdbProp(pHdb node, char *key);
/**
* initialize a property scan on this node
* @param node The node for which to scan properties

View File

@ -834,7 +834,7 @@ void HistDirty(pHistMem self)
return 0;
}
if(iEnd > iDataLen/sizeof(HistInt))
if( (iEnd -iStart) > iDataLen/sizeof(HistInt))
{
SCWrite(pCon,"WARNING: truncating request to fit data space",eWarning);
iEnd = (iDataLen/sizeof(HistInt)) - 1;
@ -1138,7 +1138,7 @@ static int checkHMEnd(pHistMem self, char *text){
return 0;
}
memset(pBuf,0,iRet+60);
HistGetOption(self,argv[2],pBuf,iRet);
HistGetOption(self,argv[2],pBuf,iRet+60);
sprintf(pBueffel,"%s.%s = %s",argv[0],argv[2],pBuf);
SCWrite(pCon,pBueffel,eValue);
free(pBuf);

View File

@ -21,7 +21,7 @@ $\langle$Modes {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ ePSD,@\\
\mbox{}\verb@ eSANSTOF@\\
\mbox{}\verb@ } HistMode;@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -59,7 +59,7 @@ $\langle$Modes {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ eOCount,@\\
\mbox{}\verb@ eReflect@\\
\mbox{}\verb@ } OverFlowMode;@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -176,7 +176,7 @@ $\langle$HistType {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int (*FreePrivate)(pHistDriver self);@\\
\mbox{}\verb@ void *pPriv;@\\
\mbox{}\verb@ } HistDriver;@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -279,7 +279,9 @@ $\langle$HistDrivProt {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ void DeleteHistDriver(pHistDriver self);@\\
\mbox{}\verb@ int HistDriverConfig(pHistDriver self, pStringDict pOpt,@\\
\mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@ HistInt *DefaultSubSample(pHistDriver self, SConnection *pCon, @\\
\mbox{}\verb@ int bank, char *command); @\\
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -318,7 +320,7 @@ $\langle$HistST {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ pICountable pCountInt;@\\
\mbox{}\verb@ pICallBack pCall;@\\
\mbox{}\verb@ } HistMem;@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -360,7 +362,7 @@ $\langle$Protos {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@@\\
\mbox{}\verb@ pHistMem CreateHistMemory(char *drivername);@\\
\mbox{}\verb@ void DeleteHistMemory(void *self);@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -390,7 +392,7 @@ $\langle$Protos {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int HistGetOption(pHistMem self, char *name, char *result, int iResultLen);@\\
\mbox{}\verb@ int HistSetOption(pHistMem self, char *name, char *value);@\\
\mbox{}\verb@ int HistConfigure(pHistMem self, SConnection *pCon, SicsInterp *pSics);@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -441,7 +443,7 @@ $\langle$Protos {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int HistBlockCount(pHistMem self, SConnection *pCon);@\\
\mbox{}\verb@ void HistDirty(pHistMem self); @\\
\mbox{}\verb@@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -481,7 +483,7 @@ $\langle$Protos {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int i, int iStart, int iEnd, @\\
\mbox{}\verb@ HistInt *lData, int iDataLen);@\\
\mbox{}\verb@ int PresetHistogram(pHistMem self, SConnection *pCon, HistInt lVal);@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -535,7 +537,7 @@ $\langle$Protos {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int HistAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ @\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-1ex}
\footnotesize\addtolength{\baselineskip}{-1ex}
@ -597,7 +599,7 @@ following.
\mbox{}\verb@@$\langle$Protos {\footnotesize ?, \ldots\ }$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
@ -623,7 +625,7 @@ following.
\mbox{}\verb@@$\langle$HistDrivProt {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]
@ -646,7 +648,7 @@ following.
\mbox{}\verb@@$\langle$HistST {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@@\\
\mbox{}\verb@#endif@\\
\mbox{}\verb@@$\diamond$
\mbox{}\verb@@$\Diamond$
\end{list}
\vspace{-2ex}
\end{minipage}\\[4ex]

View File

@ -234,6 +234,8 @@ only these few functions operate on histogram memory drivers in general:
void DeleteHistDriver(pHistDriver self);
int HistDriverConfig(pHistDriver self, pStringDict pOpt,
SConnection *pCon);
HistInt *DefaultSubSample(pHistDriver self, SConnection *pCon,
int bank, char *command);
@}
CreateHistDriver creates a new HistDriver data structure and returns it. Or

View File

@ -204,7 +204,13 @@
int i, int iStart, int iEnd, HistInt *lData)
{
iSet = 2;
if(self->data->localBuffer == NULL){
resizeBuffer(self->data);
}
iSetVal = lData[0];
if(iEnd <= getHMDataLength(self->data)){
memcpy(self->data->localBuffer+iStart,lData,(iEnd - iStart)*sizeof(HistInt));
}
return 1;
}
@ -244,6 +250,21 @@
return pDriv->fTime;
}
/*-------------------------------------------------------------------------*/
HistInt *DefaultSubSample(pHistDriver self, SConnection *pCon,
int bank, char *command){
HistInt *data = NULL;
char error[132];
assert(bank == 0); /* no bank handling yet.. */
memset(error,0,132*sizeof(char));
data = subSample(self->data, command, error, 132);
if(data == NULL){
SCWrite(pCon,error,eError);
}
return data;
}
/*-------------------------------------------------------------------------*/
pHistDriver CreateSIMHM(pStringDict pOpt)
{
@ -280,6 +301,7 @@
pNew->FreePrivate = SimFreePrivate;
pNew->Pause = SimPause;
pNew->Continue = SimContinue;
pNew->SubSample = DefaultSubSample;
StringDictAddPair(pOpt,"failrate","-1");
return pNew;

6
hkl.c
View File

@ -52,7 +52,10 @@
return 1;
}
fprintf(fd,"#Crystallographic Settings\n");
if(self->iManual == 1)
{
fprintf(fd,"%s lambda %f\n",name, self->fLambda);
}
fprintf(fd,
"%s setub %8.6f %8.6f %8.6f %8.6f %8.6f %8.6f %8.6f %8.6f %8.6f\n",
name,
@ -1296,6 +1299,9 @@ ente:
double z1[3];
int i;
if(self->UBinv == NULL){
return 0;
}
z1FromAngles(self->fLambda,tth,om,chi,phi,z1);
z1m = vectorToMatrix(z1);
/* multiply with UBinv in order to yield HKL */

153
hmdata.c
View File

@ -16,10 +16,12 @@
#include "splitter.h"
#include "fortify.h"
#include "hmdata.h"
#include <nxdataset.h>
#include "HistMem.h"
#include "HistMem.i"
#include "HistDriv.i"
#include "countdriv.h"
#include "stptok.h"
/*----------------------------------------------------------------------*/
pHMdata makeHMData(void) {
pHMdata self = NULL;
@ -484,4 +486,155 @@ int loadHMData(pHMdata self, SConnection *pCon, char *filename){
fclose(fd);
return 1;
}
/*==========================================================================
* subsampling was stolen from the SinqHTTP histogram memory code and
* thus contains some additional indirections.
* =========================================================================*/
static pNXDS hmDataToNXDataset(pHMdata self){
pNXDS result = NULL;
int i;
result = malloc(sizeof(NXDS));
if(result == NULL){
return NULL;
}
memset(result,0,sizeof(NXDS));
result->magic = MAGIC;
result->type = NX_INT32;
result->rank = self->rank;
if(isInTOFMode(self)){
result->rank++;
}
result->dim = malloc(self->rank*sizeof(int));
if(result->dim == NULL){
free(result);
return NULL;
}
for(i = 0; i < self->rank; i++){
result->dim[i] = self->iDim[i];
}
if(isInTOFMode(self)){
result->dim[result->rank-1] = getNoOfTimebins(self);
}
if(self->localBuffer == NULL){
resizeBuffer(self);
}
result->u.iPtr = self->localBuffer;
return result;
}
/*---------------------------------------------------------------------------*/
static pNXDS subSampleCommand(pNXDS source, char *command,
char *error, int errLen){
int startDim[NX_MAXRANK], endDim[NX_MAXRANK];
int dim = 0, start = 0, i;
char *pPtr = NULL, token[80];
pPtr = stptok(command,token,79,":\0");
while((pPtr = stptok(pPtr,token,79,":\0")) != NULL){
if(start == 0){
startDim[dim] = atoi(token);
start = 1;
} else {
endDim[dim] = atoi(token);
start = 0;
dim++;
}
}
if(dim < source->rank - 1){
strncpy(error,"ERROR: Not enough border values specified for subsampling",errLen);
return NULL;
}
for(i = 0; i < source->rank; i++){
if(startDim[i] < 0 || startDim[i] >= source->dim[i]){
snprintf(error,errLen,"ERROR: invalid start value %d for dimension %d", startDim[1], i);
return NULL;
}
if(endDim[i] < startDim[i] || endDim[i] >= source->dim[i]){
snprintf(error,errLen,"ERROR: invalid end value %d for dimension %d", endDim[1], i);
return NULL;
}
}
return cutNXDataset(source,startDim,endDim);
}
/*-----------------------------------------------------------------------------*/
static pNXDS sumCommand(pNXDS source, char *command, char *error, int errlen){
int dimNo = -1, start = -1, end = -1;
char *pPtr = NULL;
char token[80];
pPtr = stptok(command,token,79,":\0");
pPtr = stptok(pPtr,token,79,":\0");
if(pPtr != NULL){
dimNo = atoi(token);
}
pPtr = stptok(pPtr,token,79,":\0");
if(pPtr != NULL){
start = atoi(token);
}
pPtr = stptok(pPtr,token,79,":\0");
if(pPtr != NULL){
end = atoi(token);
}
if(dimNo < 0 || dimNo > source->rank - 1){
snprintf(error,errlen,"ERROR: invalid dimension %d requestd to sum", dimNo);
return NULL;
}
if(end < 0 || end > source->dim[dimNo] || start < 0 || start > end){
snprintf(error,errlen,"ERROR: invalid summing limits %d to %d requested", start,end);
return NULL;
}
return sumNXDataset(source,dimNo, start, end);
}
/*--------------------------------------------------------------------------*/
HistInt *subSample(pHMdata self, char *command,
char *error, int errLen){
pNXDS source = NULL, start = NULL;
pNXDS result = NULL;
char *pPtr = NULL;
char subCommand[132];
HistInt *data = NULL;
int length;
start = hmDataToNXDataset(self);
if(start == NULL){
strncpy(error,"Out-Of-Memory or no data while subsampling ",
errLen);
return NULL;
}
source = start;
pPtr = command;
while((pPtr = stptok(pPtr,subCommand,131,";\0\r\n")) != NULL){
if(strstr(subCommand,"sample") != NULL){
result = subSampleCommand(source,subCommand,error, errLen);
} else if(strstr(subCommand,"sum") != NULL){
result = sumCommand(source,subCommand,error, errLen);
} else {
strncpy(error,"ERROR: invalid subcommand to process requested",errLen);
return NULL;
}
if(result == NULL){
return NULL;
}
if(source != start){
dropNXDataset(source);
}
source = result;
}
length = getNXDatasetLength(result);
data = malloc((length+1)*sizeof(int));
if(data == NULL){
strncpy(error,"Out-Of-Mmeory in Subsample", errLen);
dropNXDataset(result);
return NULL;
}
data[0] = length;
memcpy(data+1,result->u.iPtr, length*sizeof(int));
dropNXDataset(result);
return data;
}

View File

@ -60,6 +60,8 @@
int start[MAXDIM], int end[MAXDIM]);
int loadHMData(pHMdata self, SConnection *pCon, char *filename);
HistInt *subSample(pHMdata self, char *command,
char *error, int errLen);
#endif

293
hmslave.c Normal file
View File

@ -0,0 +1,293 @@
/**
* This is a histogram memory driver for a slave histogram. This is for
* supporting multiple banks of histogram memory data in one physical
* histogram memory, possibly with different dimensions. On HM will connect
* to the physical histogram memory server and configure and control it and
* also handle bank 0. Other HM's may use this slave drive to to connect to
* the main HM for retrieving further banks. Thus this HM just becomes a
* data container for bank data. And this is the driver for such slave HM's.
* It mostly implements empty functions as control is through the main HM. The
* execption is data loading which will load the associated bank from the
* main HM.
*
* This is as of March 2007 defunct. The reason is that there are problems
* with buffering the data.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, March 2007
*/
#include <sics.h>
#include <countdriv.h>
#include <counter.h>
#include <HistMem.h>
#include <HistMem.i>
#include <stringdict.h>
#include <HistDriv.i>
#include <hmdata.h>
typedef struct {
pHistMem master;
int bank;
}*HMSlave, sHMSlave;
/*-------------------------------------------------------------------
Configures the HM from the options in pOpt and the HM data structure
Returns 1 on success, 0 on failure
---------------------------------------------------------------------*/
static int HMSlaveConfigure(pHistDriver self, SConnection *pCon,
pStringDict pOpt, SicsInterp *pSics){
HMSlave pPriv = NULL;
char buffer[80], error[256];
pPriv =(HMSlave)self->pPriv;
if(StringDictGet(pOpt,"master",buffer, 79) == 1){
pPriv->master = (pHistMem)FindCommandData(pServ->pSics,buffer,"HistMem");
if(pPriv->master == NULL){
snprintf(error,255,"ERROR: failed to find master HM %s", buffer);
SCWrite(pCon,error,eError);
return 0;
}
} else {
SCWrite(pCon,"ERROR: required configuration option master missing",
eError);
return 0;
}
if(StringDictGet(pOpt,"bank",buffer, 79) == 1){
pPriv->bank = atoi(buffer);
} else {
SCWrite(pCon,"ERROR: required configuration option bank missing",
eError);
return 0;
}
return 1;
}
/*--------------------------------------------------------------------
Start histogramming, Returns HWFault on failure, 1 on success
----------------------------------------------------------------------*/
static int HMSlaveStart(pHistDriver self,SConnection *pCon){
HMSlave pPriv = NULL;
pPriv =(HMSlave)self->pPriv;
return 1;
}
/*--------------------------------------------------------------------
Stops histogramming, Returns HWFault on failure, 1 on success
----------------------------------------------------------------------*/
static int HMSlaveHalt(pHistDriver self){
HMSlave pPriv = NULL;
pPriv =(HMSlave)self->pPriv;
return 1;
}
/*--------------------------------------------------------------------
Checks histogramming status, Returns HWFault on failure,
HWIdle when finished, HWBusy when counting
----------------------------------------------------------------------*/
static int HMSlaveCountStatus(pHistDriver self,SConnection *pCon){
HMSlave pPriv = NULL;
pPriv =(HMSlave)self->pPriv;
return HWIdle;
}
/*--------------------------------------------------------------------
Get info on error after last HWFault, returns 1 always.
Puts an int error code into *code and errLen chars of
error description into error
----------------------------------------------------------------------*/
static int HMSlaveGetError(pHistDriver self,int *code,
char *error, int errLen){
HMSlave pPriv = NULL;
pPriv =(HMSlave)self->pPriv;
strncpy(error,"Weird status: slaves do not err..",errLen);
*code = -77;
return 1;
}
/*--------------------------------------------------------------------
Try to fix the HM error in code. Returns COREDO when the last
operation needs to be redone, COTERM when the error cannot be
fixed.
----------------------------------------------------------------------*/
static int HMSlaveFixIt(pHistDriver self,int code){
HMSlave pPriv = NULL;
pPriv =(HMSlave)self->pPriv;
return COTERM;
}
/*--------------------------------------------------------------------
GetData reads updates the internal cache of monitor values
from the hardware, Returns 1 or HWFault
----------------------------------------------------------------------*/
static int HMSlaveGetData(pHistDriver self,SConnection *pCon){
HMSlave pPriv = NULL;
pPriv =(HMSlave)self->pPriv;
return 1;
}
/*--------------------------------------------------------------------
GetMonitor reads the monitor value i. Returns either the monitor
value or -9999 if no such monitor exists or an error occurred
----------------------------------------------------------------------*/
static long HMSlaveGetMonitor(pHistDriver self,int i, SConnection *pCon){
HMSlave pPriv = NULL;
pPriv =(HMSlave)self->pPriv;
return -9999;
}
/*--------------------------------------------------------------------
GetTime reads the total counting time. Returns either the
value or -9999.99 if no such value exists or an error occurred
----------------------------------------------------------------------*/
static float HMSlaveGetTime(pHistDriver self,SConnection *pCon){
HMSlave pPriv = NULL;
pPriv =(HMSlave)self->pPriv;
return -9999.99;
}
/*--------------------------------------------------------------------
Pause histogramming, Returns HWFault on failure, 1 on success
----------------------------------------------------------------------*/
static int HMSlavePause(pHistDriver self,SConnection *pCon){
HMSlave pPriv = NULL;
pPriv =(HMSlave)self->pPriv;
return 1;
}
/*--------------------------------------------------------------------
Continue histogramming, Returns HWFault on failure, 1 on success
----------------------------------------------------------------------*/
static int HMSlaveContinue(pHistDriver self,SConnection *pCon){
HMSlave pPriv = NULL;
pPriv =(HMSlave)self->pPriv;
return 1;
}
/*--------------------------------------------------------------------
Free the data associated with the private data structure of the driver
----------------------------------------------------------------------*/
static int HMSlaveFree(pHistDriver self){
HMSlave pPriv = NULL;
pPriv =(HMSlave)self->pPriv;
if(pPriv != NULL){
free(pPriv);
}
self->pPriv = NULL;
return 1;
}
/*-------------------------------------------------------------------
* fixTimebinning assures that our time binning dn the masters
* time binning are the same. So that diemsnions are right
* ------------------------------------------------------------------*/
static int fixTimeBinning(pHistDriver self, SConnection *pCon){
HMSlave pPriv = NULL;
pPriv =(HMSlave)self->pPriv;
if(isInTOFMode(pPriv->master->pDriv->data) &&
getNoOfTimebins(pPriv->master->pDriv->data) !=
getNoOfTimebins(self->data)){
self->data->tofMode = 1;
self->data->nTimeChan = getNoOfTimebins(pPriv->master->pDriv->data);
if(!resizeBuffer(self->data)) {
SCWrite(pCon,
"ERROR: out of memory allocating HMData for slave",
eError);
return 0;
}
}
return 1;
}
/*--------------------------------------------------------------------
Set The HM data or a subset of it. Returns HWFault or 1
----------------------------------------------------------------------*/
static int HMSlaveSetHistogram(pHistDriver self,
SConnection *pCon,
int i, int iStart, int iEnd, HistInt *pData){
HMSlave pPriv = NULL;
HistInt *start = NULL;
pPriv =(HMSlave)self->pPriv;
if(fixTimeBinning(self,pCon) == 1){
start = self->data->localBuffer + iStart;
memcpy(start,pData,(iEnd - iStart)*sizeof(HistInt));
return 1;
} else {
return 0;
}
}
/*--------------------------------------------------------------------
Set HM to a preset value, Returns HWFault on failure, 1 on success
----------------------------------------------------------------------*/
static int HMSlavePreset(pHistDriver self,SConnection *pCon,
HistInt value){
HMSlave pPriv = NULL;
int i;
pPriv =(HMSlave)self->pPriv;
if(fixTimeBinning(self,pCon) == 1){
for(i = 0; i < getHMDataLength(self->data); i++){
self->data->localBuffer[i] = value;
}
return 1;
} else {
return 0;
}
}
/*--------------------------------------------------------------------
get The HM data or a subset of it. Returns HWFault or 1
----------------------------------------------------------------------*/
static int HMSlaveGetHistogram(pHistDriver self,
SConnection *pCon,
int i, int iStart, int iEnd, HistInt *pData){
HMSlave pPriv = NULL;
pPriv = (HMSlave)self->pPriv;
return pPriv->master->pDriv->GetHistogram(pPriv->master->pDriv,
pCon, pPriv->bank, iStart, iEnd, pData);
}
/*--------------------------------------------------------------------
Make the HMDriver, returns a driver or NULL on failure
----------------------------------------------------------------------*/
pHistDriver MakeHMSlaveHM(pStringDict pOption){
pHistDriver pNew = NULL;
HMSlave pPriv = NULL;
/* create the general driver */
pNew = CreateHistDriver(pOption);
if(!pNew){
return NULL;
}
/*Create private data structure*/
pPriv = (HMSlave)malloc(sizeof(sHMSlave));
if(pPriv == NULL){
return NULL;
}
pNew->pPriv = pPriv;
/* add our options */
StringDictAddPair(pOption,"master","unknown");
StringDictAddPair(pOption,"bank","1");
/* configure all those functions */
pNew->Configure = HMSlaveConfigure;
pNew->Start = HMSlaveStart;
pNew->Halt = HMSlaveHalt;
pNew->GetCountStatus = HMSlaveCountStatus;
pNew->GetError = HMSlaveGetError;
pNew->TryAndFixIt = HMSlaveFixIt;
pNew->GetData = HMSlaveGetData;
pNew->GetHistogram = HMSlaveGetHistogram;
pNew->SetHistogram = HMSlaveSetHistogram;
pNew->GetMonitor = HMSlaveGetMonitor;
pNew->GetTime = HMSlaveGetTime;
pNew->Preset = HMSlavePreset;
pNew->FreePrivate = HMSlaveFree;
pNew->Pause = HMSlavePause;
pNew->Continue = HMSlaveContinue;
return pNew;
}

View File

@ -49,11 +49,12 @@
static IPair *CreateNewEntry(char *name, char *val, IPair *pN)
{
IPair *pRes;
IPair *pRes = NULL;
pRes = (IPair *)malloc(sizeof(IPair));
if(!pRes)
return NULL;
memset(pRes,0,sizeof(IPair));
if(name)
pRes->name = strdup(name);
if(val)

View File

@ -9,12 +9,13 @@ Markus Zolliker, March 2005
#include "sics.h"
#include "initializer.h"
#include "splitter.h"
typedef struct Item {
struct Item *next;
char *type;
char *name;
char *desc;
char *type; /* "Object" for all commands created by makeobject, else something more general */
char *name; /* the name for identifying an initializer */
char *desc; /* a description of the initializer. not the same as pObjectDescriptor->name */
Initializer maker;
int startupOnly;
} Item;
@ -40,7 +41,7 @@ void MakeInitializer(const char *type, const char *name, Initializer maker,
Initializer GetInitializer(const char *type, const char *name) {
Item *p, **last;
if (startup && pServ->pReader != NULL) {
if (startup && !ServerIsStarting(pServ)) {
/* pServ->pReader exists: startup finished */
startup = 0;
/* remove startup initializers */
@ -57,30 +58,26 @@ Initializer GetInitializer(const char *type, const char *name) {
}
}
}
p = list;
while (p != NULL && (strcasecmp(p->name, name) != 0 || strcasecmp(p->type, type) != 0)) {
p = p->next;
}
if (p) {
for (p = list; p != NULL; p = p->next) {
if (strcasecmp(p->name, name) == 0 && strcasecmp(p->type, type) == 0) {
return p->maker;
}
}
return NULL;
}
static int MakeObject(SConnection *con, SicsInterp *sics,
void *data, int argc, char *argv[]) {
CmdInitializer cmdin;
CommandList *command;
char *className;
if (argc < 3) {
SCPrintf(con, eError, "%s needs more arguments", argv[0]);
SCPrintf(con, eError, "ERROR: should be: %s <object> <type> ...", argv[0]);
return 0;
}
cmdin = (CmdInitializer)GetInitializer("Object", argv[2]);
if (cmdin) {
return cmdin(con, argc, argv, ! startup);
return cmdin(con, argc, argv, strcasecmp(argv[0],"makeobject") == 0);
} else {
SCPrintf(con, eError, "do not know how to make a %s object", argv[2]);
return 0;
@ -124,23 +121,43 @@ static int DriverList(SConnection *con, SicsInterp *sics,
static int RemoveObject(SConnection *con, SicsInterp *sics,
void *data, int argc, char *argv[]) {
CmdInitializer cmdin;
CommandList *command;
ObjectDescriptor *desc;
char *className;
char shortClassName[32];
char *p;
int removeAllowed;
char *creationCommand;
if (argc != 2) {
SCPrintf(con, eError, "%s needs 1 argument", argv[0]);
SCPrintf(con, eError, "ERROR: should be: %s <object>", argv[0]);
return 0;
}
command = FindCommand(sics, argv[1]);
if (!command) {
desc = FindCommandDescriptor(sics, argv[1]);
if (!desc) {
SCPrintf(con, eError, "ERROR: %s not found", argv[1]);
return 0;
}
className = ((pDummy)command->pData)->pDescriptor->name;
creationCommand = GetDescriptorKey(desc, "creationCommand");
if (creationCommand != NULL) {
/* if there is a creationCommand, we are allowed to remove */
removeAllowed = 1;
} else {
/* if we have an initializer: we are also allowed to remove */
className = desc->name;
cmdin = (CmdInitializer)GetInitializer("Object", className);
if (cmdin) {
/* if we have an initializer, we are allowed to remove */
if (cmdin == 0) {
/* allow also a longer descriptor starting with the initializer name and a blank */
p = strchr(className, ' ');
if (p) {
snprintf(shortClassName, sizeof shortClassName, "%.*s", p - className, className);
cmdin = (CmdInitializer)GetInitializer("Object", shortClassName);
}
}
removeAllowed = (cmdin != NULL);
}
if (removeAllowed) {
if (pServ->pExecutor && isInRunMode(pServ->pExecutor)) {
SCPrintf(con, eError, "ERROR: cannot remove %s while running", argv[1]);
return 0;
@ -154,6 +171,82 @@ static int RemoveObject(SConnection *con, SicsInterp *sics,
}
}
typedef struct {
int printHeader;
FILE *fil;
} SaveData;
static int SaveCreationCommand(char *name, pDummy object, void *userData) {
SaveData *saveData = userData;
char *creationCommand;
creationCommand = GetDescriptorKey(object->pDescriptor, "creationCommand");
if (creationCommand && strcmp(creationCommand, "0") != 0) {
if (saveData->printHeader == 0) {
saveData->printHeader = 1;
fprintf(saveData->fil, "\n#--- BEGIN creation commands\n");
}
fprintf(saveData->fil, "%s\n", creationCommand);
}
return 1;
}
static int SaveCreationCommands(void *object, char *name, FILE *fil) {
SaveData saveData;
saveData.fil = fil;
saveData.printHeader = 0;
ForEachCommand(SaveCreationCommand, &saveData);
if (saveData.printHeader == 1) {
fprintf(fil, "#--- END creation commands\n\n");
}
return 1;
}
static int CreationCommand(SConnection *con, SicsInterp *sics,
void *data, int argc, char *argv[]) {
CmdInitializer cmdin;
char *className;
char shortClassName[32];
char *p;
int removeAllowed;
ObjectDescriptor *desc;
char *creationCommand;
char buf[256];
if (argc < 2) {
SCPrintf(con, eError, "ERROR: should be: %s <object> [<creation command>]", argv[0]);
return 0;
}
desc = FindCommandDescriptor(sics, argv[1]);
if (!desc) {
SCPrintf(con, eError, "ERROR: %s not found", argv[1]);
return 0;
}
creationCommand = GetDescriptorKey(desc, "creationCommand");
if (argc < 3) {
if (creationCommand != NULL) {
SCPrintf(con, eValue, "%s", creationCommand);
} else {
SCPrintf(con, eValue, "<static object>");
}
} else {
if (!creationCommand) {
SCPrintf(con, eValue, "ERROR: %s is a static object", argv[1]);
return 0;
}
creationCommand = Arg2Tcl(argc - 2, argv + 2, buf, sizeof buf);
if (creationCommand) {
SetDescriptorKey(desc, "creationCommand", creationCommand);
if (creationCommand != buf) free(creationCommand);
} else {
SetDescriptorKey(desc, "creationCommand", "0");
}
}
return 1;
}
static void KillInitializers(void *data) {
KillDummy(data);
Item *item, *next;
@ -171,10 +264,17 @@ static void KillInitializers(void *data) {
}
void MakeDriver(const char *driver, CmdInitializer maker, int startupOnly, const char *desc) {
if (! FindCommand(pServ->pSics, "MakeObject")) {
AddCommandWithFlag(pServ->pSics, "MakeObject", MakeObject, KillInitializers, NULL, 0);
AddCommandWithFlag(pServ->pSics, "RemoveObject", RemoveObject, NULL, NULL, 0);
AddCommandWithFlag(pServ->pSics, "DriverList", DriverList, NULL, NULL, 0);
}
MakeInitializer("Object", driver, (Initializer)maker, startupOnly, desc);
}
void InitializerInit(void) {
pDummy cc = NULL;
AddCommandWithFlag(pServ->pSics, "MakeObject", MakeObject, KillInitializers, NULL, 0);
AddCommandWithFlag(pServ->pSics, "MakeStaticObject", MakeObject, NULL, NULL, 0);
AddCommandWithFlag(pServ->pSics, "RemoveObject", RemoveObject, NULL, NULL, 0);
AddCommandWithFlag(pServ->pSics, "DriverList", DriverList, NULL, NULL, 0);
cc = CreateDummy("creation commands");
cc->pDescriptor->SaveStatus = SaveCreationCommands;
AddCommandWithFlag(pServ->pSics, "CreationCommand", CreationCommand,
KillDummy, cc, 0);
}

View File

@ -33,16 +33,19 @@ Initializer GetInitializer(const char *type, const char *name);
type.
*/
/*
static int MakeObject(SConnection *con, SicsInterp *sics,
void *data, int argc, char *argv[]);
/*
MakeObject has the following syntax:
MakeObject objectName driver [ args ... ]
It executes the initializer with the type "Object" and and the
driver given as name. The found initalizer should use the given arguments
to create a driver.
to create a driver. Objects should be dynamic, i.e. there should be
a creation command in the status file, except when the creation command
was MakeStaticObject instead of MakeObject.
*/
@ -52,7 +55,8 @@ typedef int (*CmdInitializer) (SConnection *pCon, int argc, char *argv[], int dy
- pCon: the sics connection calling this initializer
- argc: the total number of args
- argv: the args (argv[0]: "MakeObject", argv[1]: object name, argv[3]: driver ...)
- dynamic: the initializer was called _after_ startup
- dynamic: 1, if the creation command was MakeObject,
0, if the creation command was MakeStaticObject
*/
void MakeDriver(const char *driver, CmdInitializer maker, int startupOnly,

View File

@ -28,6 +28,21 @@ int LLDblobCreate( void )
return LLDcreate( sizeof( struct BlobDesc ));
}
/*---------------------------------------------------------------------*/
int LLDdeleteBlob(int List)
{
struct BlobDesc Blob ;
int status;
status = LLDnodePtr2First(List);
while(status == 1){
LLDnodeDataTo( List, & Blob );
free(Blob.data);
status = LLDnodePtr2Next(List);
}
LLDdelete(List);
return 1;
}
/* ---- LL blob node mangement ---------------------------------------- */
int LLDblobInsert( int List, void * Source, unsigned Size )

View File

@ -20,7 +20,8 @@
int LLDblobCreate( void );
/* returns list number to use or -1 on failure. */
/* MUST be called before using a list of blobs. */
int LLDdeleteBlob(int List);
/* deletes a list and all its data */
/* ---- Node management --------------------------------------------------
Functions changing current node pointer to the new node.
A return value of -1 indicates a memory allocation problem.

369
logger.c Normal file
View File

@ -0,0 +1,369 @@
/*---------------------------------------------------------------------------
logger.c
Markus Zolliker, Sept 2004
----------------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <fortify.h>
#include <errno.h>
#include <ctype.h>
#include "logger.h"
struct Logger {
char *name;
char *old;
int oldsize;
int period;
time_t last, lastWrite;
int numeric;
int exact;
Logger *next;
};
static char *dir = NULL;
static Logger *list;
static time_t lastLife = 0;
static time_t lastWritten = 0;
/*--------------------------------------------------------------------------*/
char *LoggerName(Logger *log) {
return log->name;
}
/*--------------------------------------------------------------------------*/
void LoggerSetNumeric(Logger *log, int numeric) {
if (log) {
log->numeric = numeric;
}
}
/*--------------------------------------------------------------------------*/
Logger *LoggerFind(const char *name) {
Logger *p;
p = list;
while (p != NULL) {
if (0==strcasecmp(name, p->name)) {
return p;
}
p = p->next;
}
return NULL;
}
/*--------------------------------------------------------------------------*/
#define LASTLOGTXT "#last logging entry at:\n"
time_t LoggerGetLastLife(char *dirarg) {
char path[256], line[32];
FILE *fil;
time_t t = 0;
if (dirarg == NULL) {
return lastWritten;
}
snprintf(path, sizeof path, "%s/lastlife.dat", dirarg);
fil = fopen(path, "r");
if (fil) {
fgets(line, sizeof line, fil);
if (strcmp(line, LASTLOGTXT) == 0) {
fgets(line, sizeof line, fil);
t = atol(line);
if (t < 1000000000) {
printf("bad lastLife %ld\n", (long)t);
}
}
fclose(fil);
} else {
/* printf("can not read %s\n", path); */
}
return t;
}
/*--------------------------------------------------------------------------*/
time_t LoggerSetDir(char *dirarg) {
dir = dirarg;
lastLife = LoggerGetLastLife(dir);
return lastLife;
}
/*--------------------------------------------------------------------------*/
char *LoggerGetDir(void) {
char path[256];
FILE *fil;
static time_t last;
lastWritten = time(NULL);
if (lastWritten != last) { /* do not write more than once per second */
snprintf(path, sizeof path, "%s/lastlife.dat", dir);
fil = fopen(path, "w");
if (fil) {
fprintf(fil, "%s%ld\n", LASTLOGTXT, (long)lastWritten);
fclose(fil);
} else {
printf("can not write %s\n", path);
}
last = lastWritten;
}
return dir;
}
/*--------------------------------------------------------------------------*/
int LoggerVarPath(char *dir, char *path, int pathLen, char *name, struct tm *t) {
int l;
l = strlen(dir);
if (l + strlen(name) + 8 >= pathLen) {
path[0]='\0';
return 0;
}
strcpy(path, dir);
strftime(path + l, pathLen - l, "/%Y/", t);
l += 6;
for (;*name != '\0'; name++, l++) {
path[l] = tolower(*name);
}
path[l] = '/'; l++;
path[l] = '\0';
return l;
}
/*--------------------------------------------------------------------------*/
int LoggerWrite0(Logger *log, time_t now, int period, char *value) {
char path[256], stim[32], buf[32];
struct tm tm, lasttm;
int l, ext, writeInfo;
FILE *fil;
time_t beforenow;
LoggerGetDir();
if (dir == NULL) return 0;
if (now == 0) {
printf("now==0\n");
}
lasttm = *localtime(&log->last);
tm = *localtime(&now);
l = LoggerVarPath(dir, path, sizeof path, log->name, &tm);
strftime(path + l, sizeof path - l, "%m-%d.log", &tm);
strftime(stim, sizeof stim, "#%Y-%m-%d %H:%M:%S", &tm);
if (period <= 0) period = 1;
writeInfo = (tm.tm_isdst != lasttm.tm_isdst ||
tm.tm_yday != lasttm.tm_yday ||
(period != log->period && log->numeric));
if (strcmp(value, log->old) != 0 || writeInfo) {
fil = fopen(path, "r+");
if (fil == NULL) { /* create new file */
fil = fopen(path, "w+");
if (fil == NULL) return 0;
fprintf(fil, "%s isdst %d period %d exact %d\n", stim, tm.tm_isdst, period, log->exact);
} else { /* check if file is from today */
fgets(buf, sizeof buf, fil);
if (0 != strncmp(buf, stim, 11)) {
fclose(fil); /* it was file from an earlier year */
fil=fopen(path, "w+"); /* overwrite old logfile */
if (fil == NULL) return 0;
fprintf(fil, "%s isdst %d period %d exact %d\n", stim, tm.tm_isdst, period, log->exact);
} else {
fseek(fil, 0, SEEK_END); /* set position to end */
if (writeInfo) {
fprintf(fil, "#isdst %d period %d exact %d\n", tm.tm_isdst, period, log->exact);
}
if (log->lastWrite != 0 && now >= log->lastWrite + 2 * period) {
/* this is only useful for direct access of the log files */
beforenow = now - period;
lasttm = *localtime(&beforenow);
if (lasttm.tm_yday == tm.tm_yday) {
strftime(stim, sizeof stim,"%H:%M:%S", &lasttm);
} else {
snprintf(stim, sizeof stim, "00:00:00");
}
fprintf(fil, "%s\t%s\n", stim, log->old);
}
}
}
strftime(stim, sizeof stim,"%H:%M:%S", &tm);
fprintf(fil, "%s\t%s\n", stim, value);
log->lastWrite = now;
fclose(fil);
}
log->period = period;
l = strlen(value);
if (l >= log->oldsize) { /* increase log->old size, optimized for linux/i386 */
ext = ((l - log->oldsize)/16 + 1) * 16;
if (ext < log->oldsize / 4) ext += (log->oldsize / 64) * 16;
log->oldsize += ext;
free(log->old);
log->old = calloc(1, log->oldsize);
}
assert(log->old);
assert(l < log->oldsize);
strcpy(log->old, value);
assert(log->old[l] == '\0');
log->last = now;
return 1;
}
/*--------------------------------------------------------------------------*/
int LoggerWrite(Logger *log, time_t now, int period, char *value) {
Logger *p;
time_t h0;
static int yday = -1;
struct tm *tm;
int l;
FILE *fil;
char path[256];
char tim[256];
tm = localtime(&now);
if (tm->tm_yday != yday) {
tm->tm_hour = 0;
tm->tm_min = 0;
tm->tm_sec = 0;
h0 = mktime(tm);
yday = tm->tm_yday;
/* -- debug logging if dir/debug exists */
l = LoggerVarPath(dir, path, sizeof path, "debug", tm);
strftime(path + l, sizeof path - l, "%m-%d.log", tm);
fil=fopen(path, "a");
if (fil) {
strftime(tim, sizeof tim, "h0 %m-%d %H:%M:%S\n", localtime(&h0));
fputs(tim, fil);
}
/* log old values (forced midnight log) */
p = list;
while (p != NULL) {
if (fil) { /* debug logging */
strftime(tim, sizeof tim, "last %m-%d %H:%M:%S, ", localtime(&p->last));
fputs(tim, fil);
fprintf(fil, "period %d, name %s, old %s\n", p->period, p->name, p->old);
}
if (p->last < h0 && p->last != 0 &&
p->period >= 0 && p->old[0] != '\0') {
LoggerWrite0(p, h0, p->period, p->old);
}
p = p->next;
}
if (fil) fclose(fil);
}
return LoggerWrite0(log, now, period, value);
}
/*--------------------------------------------------------------------------*/
time_t LoggerLastTime(Logger *log) {
if (log->last != 0 && log->period > 0) {
return log->last;
}
return 0;
}
/*--------------------------------------------------------------------------*/
int LoggerPeriod(Logger *log) {
return log->period;
}
/*--------------------------------------------------------------------------*/
void LoggerSetPeriod(Logger *log, int period) {
LoggerWrite0(log, time(NULL), period, log->old);
}
/*--------------------------------------------------------------------------*/
void LoggerKill(Logger *log) {
/* we do not really free the logger, it might be reused
for the same variable later. We set the value to undefined */
if (list != NULL) { /* LoggerFreeAll not yet called */
LoggerWrite(log, time(NULL), 0, "");
}
}
/*--------------------------------------------------------------------------*/
static int LoggerMakeDir(char *path) {
static char buffer[4096];
struct stat st;
int i, lpath, l;
char *slash;
i = stat(path, &st);
if (i >= 0) {
if (((st.st_mode >> 12) & 15) != 4) { /* exists, but is no directory */
return 0;
}
return 1;
}
i = mkdir(path, S_IRWXU+S_IRGRP+S_IXGRP+S_IROTH+S_IXOTH);
if (i < 0) {
if (errno != ENOENT) return 0; /* mkdir failed */
snprintf(buffer, sizeof buffer, "%s", path);
lpath = strlen(buffer);
do {
slash = strrchr(buffer, '/');
if (!slash) return 0;
*slash='\0';
i = mkdir(buffer, S_IRWXU+S_IRGRP+S_IXGRP+S_IROTH+S_IXOTH);
} while (i < 0 && errno == ENOENT);
l = strlen(buffer);
while (l<lpath) {
buffer[l] = '/';
i = mkdir(buffer, S_IRWXU+S_IRGRP+S_IXGRP+S_IROTH+S_IXOTH);
if (i< 0) return 0;
l = strlen(buffer);
}
}
return 1;
}
/*--------------------------------------------------------------------------*/
Logger *LoggerMake(char *name, int period, int exact) {
Logger *log;
char path[256];
time_t t;
struct tm tm;
LoggerGetDir();
if (dir == NULL) return NULL;
time(&t);
tm = *localtime(&t);
LoggerVarPath(dir, path, sizeof path, name, &tm);
if (LoggerMakeDir(path) == 0) return NULL;
log = LoggerFind(name); /* look if logger already exists */
if (log == NULL) {
log = calloc(1, sizeof *log);
if (log == NULL) return NULL;
log->name = strdup(name);
if (log->name == NULL) {
free(log);
return NULL;
}
log->period = -1;
log->exact = exact;
log->old = calloc(1,12);
log->oldsize = 12;
log->last = 0;
log->lastWrite = 0;
log->numeric = 1;
log->next = list;
list = log;
t = time(NULL) -1;
if (lastLife != 0 && lastLife + period < t) {
t = lastLife + period;
}
LoggerWrite(log, t, period, ""); /* value was undefined since last life of server */
}
return log;
}
/*--------------------------------------------------------------------------*/
void LoggerFreeAll(void) {
Logger *p, *next;
p = list;
while (p != NULL) {
next = p->next;
if (p->name) free(p->name);
if (p->old) free(p->old);
free(p);
p = next;
}
list = NULL;
}

29
logger.h Normal file
View File

@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------
logger.h
Markus Zolliker, Sept 2004
----------------------------------------------------------------------------
*/
#ifndef LOGGER_H
#define LOGGER_H
#include <time.h>
typedef struct Logger Logger;
Logger *LoggerMake(char *name, int period, int exact);
void LoggerKill(Logger *log);
int LoggerWrite(Logger *log, time_t now, int period, char *value);
char *LoggerName(Logger *log);
void LoggerSetNumeric(Logger *log, int numeric);
time_t LoggerSetDir(char *dirarg);
time_t LoggerGetLastLife(char *dirarg);
void LoggerWriteOld(Logger *log, time_t now);
time_t LoggerLastTime(Logger *log);
int LoggerPeriod(Logger *log);
void LoggerSetPeriod(Logger *log, int period);
int LoggerVarPath(char *dir, char *path, int pathLen, char *name, struct tm *t);
void LoggerFreeAll(void);
#endif

524
logreader.c Normal file
View File

@ -0,0 +1,524 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <fortify.h>
#include <errno.h>
#include <dirent.h>
#include <math.h>
#include "logger.h"
#include "sics.h"
#define LOGGER_NAN -999999.
#define ONE_YEAR (366*24*3600)
#define LLEN 1024
/* max. number of dirs in path */
#define MAX_DIRS 16
typedef enum { NUMERIC, TEXT } CompType;
typedef struct {
time_t t;
float y;
} Point;
typedef struct {
SConnection *pCon;
int exact;
CompType type;
time_t step;
time_t tlim; /* 0: initial state */
Point best; /* best point, to be written if tlim > 0 */
Point written; /* last written point */
Point last; /* last point */
char buf[LLEN];
int np;
char *none;
char *header;
time_t period;
int omitEqual;
} Compressor;
static char *dirs[MAX_DIRS] = {NULL};
static int ndirs=0;
static void InitCompressor(Compressor *c, SConnection *pCon, time_t step) {
c->pCon = pCon;
c->step = step;
c->tlim = 0;
c->last.y = LOGGER_NAN;
c->last.t = 0;
c->buf[0]='\0';
c->written.t = 0;
c->written.y = LOGGER_NAN;
c->omitEqual = 1;
}
static void OutFloat(Compressor *c, Point p) {
char *value;
if (p.y == LOGGER_NAN) {
if (c->omitEqual && c->written.y == LOGGER_NAN) return;
if (c->none) {
value = c->none;
} else {
value = "";
}
} else {
if (c->omitEqual && c->written.y == p.y) return;
snprintf(c->buf, sizeof(c->buf), "%g", p.y);
value = c->buf;
}
SCPrintf(c->pCon, eWarning, "%ld %s", (long)(p.t - c->written.t), value);
c->written = p;
c->np--;
}
static void WriteHeader(Compressor *c) {
if (c->header) {
SCPrintf(c->pCon, eWarning, "*%s period %ld\n", c->header, c->period);
c->header = NULL;
}
}
static void PutValue(Compressor *c, time_t t, char *value) {
char *p;
Point new;
WriteHeader(c);
if (c->type == NUMERIC) {
new.y = strtod(value, &p);
if (p == value) {
new.y = LOGGER_NAN;
} else {
if (new.y == LOGGER_NAN) new.y *= 1.0000002;
}
new.t = t;
if (t >= c->tlim) { /* a new interval starts */
if (c->tlim == 0) {
c->tlim = t;
} else if (c->best.y != c->written.y) {
OutFloat(c, c->best);
}
c->best = new;
c->tlim += c->step;
if (t > c->tlim) {
if (c->last.y != c->written.y) {
OutFloat(c, c->last);
}
c->tlim = t + c->step;
}
} else { /* not the first point */
if (fabs(new.y - c->best.y) > fabs(c->written.y - c->best.y)) {
c->best = new;
}
}
c->last = new;
} else if (c->type == TEXT) {
if (0 != strncmp(value, c->buf, sizeof(c->buf)-1)) {
snprintf(c->buf, sizeof(c->buf), "%s", value);
SCPrintf(c->pCon, eWarning, "%ld %s\n", (long)(t - c->written.t), value);
c->written.t = t;
c->np--;
}
}
}
static void PutFinish(Compressor *c, time_t now) {
char value[32];
if (c->tlim != 0) { /* there is data already */
c->omitEqual = 0;
if (c->type == NUMERIC) {
if (now > c->last.t + c->period) { /* copy last value to the actual time */
if (c->last.y != LOGGER_NAN) {
snprintf(value, sizeof value, "%g", c->last.y);
PutValue(c, now, value);
}
if (c->best.t > c->written.t) {
OutFloat(c, c->best); /* write last buffered value */
}
}
} if (now > c->last.t) {
PutValue(c, now, c->buf);
}
}
}
/*--------------------------------------------------------------------------*/
static long getOpt(char *line, int *isdst, int *exact) {
long lxs;
char *opt;
opt = strstr(line, "isdst");
if (opt) {
sscanf(opt, "isdst %d", isdst);
}
opt = strstr(line, "exact");
if (opt) {
sscanf(opt, "exact %d", exact);
}
opt = strstr(line, "period");
if (opt) {
sscanf(opt, "period %ld", &lxs);
return lxs;
} else {
return -1;
}
}
/*--------------------------------------------------------------------------*/
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> ...]
<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
The <none value> is optional. if not given, unknown values are returned as empty strings
<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.
<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
Output format:
First line: returning the actual time on the server (this time is used for relative times)
For each variable which has data in the given interval,
the variable name is returned preceeded by a '*', followed by some infos* separated with
blanks.
After the header line for every data point a line follows with
a time relative to the last point and the value.
The first time value relative to zero, e.g. absolute.
The data value is valid until the next datapoint. Empty values are returned as an
empty string or as the <none value>.
At the very end *<loss> <overflow> is returned.
<loss> is 1, when the data had to be reduced, 0 else
<overflow> is 1, when overflow occured, 0 else. Overflow may happen only
when np is given and a text variable was demanded.
*actually only one info exists: period <value>. This is the update rate in seconds.
As equal values are not transmitted, two points (t1,y1) and (t2,y2) with a distance
(t2 - t1) > period should not be connected directly. The plot software should generate
an intermediate point at (t2-period,y1).
*/
time_t from, to, step, xs, lastt;
char *p, *varp;
int i, j, iarg, pathLen, iret, loss, np;
int inRange;
int yday=0;
time_t t, startim;
struct tm tm;
char stim[32], path[LLEN], line[LLEN], lastval[LLEN];
char *lin, *val, *stp;
FILE *fil;
Compressor c={0};
float yy, lasty;
CompType type0;
DIR *dr;
char *opt;
int isdst;
int overflow;
time_t now, nows[MAX_DIRS], nowi;
char var[256];
char dirPathBuffer[1024];
char *dirPath;
int idir;
char *colon;
/* argtolower(argc, argv); */
if (argc < 4) goto illarg;
now = time(NULL);
from = strtol(argv[1], &p, 0); /* unix time, not year 2038 safe */
if (p == argv[1]) goto illarg;
to = strtol(argv[2], &p, 0);
if (p == argv[2]) goto illarg;
if (from < ONE_YEAR) {
from += now;
}
if (to < ONE_YEAR) {
to += now;
}
iarg = 3;
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;
} else if (strcasecmp(argv[iarg],"none") == 0) { /* none */
iarg++;
if (iarg >= argc) goto illarg;
c.none = argv[iarg];
iarg++;
} else if (strcasecmp(argv[iarg],"np") == 0) { /* max. number of points */
iarg++;
if (iarg >= argc) goto illarg;
type0 = NUMERIC;
np = strtol(argv[iarg], &p, 0);
if (p == argv[iarg]) goto illarg;
iarg++;
if (to <= from) {
step = 1;
} else if (np <= 2) {
step = to - from;
} else {
step = (to - from) / (np - 2) + 1;
}
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;
}
}
if (step <= 0) step = 1;
snprintf(line, sizeof line, "%ld\n", (long)now);
SCWrite(pCon, line, eWarning);
dirPath = IFindOption(pSICSOptions, "LogReaderPath");
if (dirPath == NULL) { /* for compatibility, check */
dirs[0] = IFindOption(pSICSOptions, "LoggerDir");
if (dirs[0] == NULL) {
SCWrite(pCon, "ERROR: LoggerPath not found", eError);
return 0;
}
nows[0] = LoggerGetLastLife(NULL);
if (dirs[1] == NULL) {
dirs[1] = IFindOption(pSICSOptions, "LoggerDir2");
nows[1] = LoggerGetLastLife(dirs[1]);
}
} else {
snprintf(dirPathBuffer, sizeof dirPathBuffer, "%s", dirPath);
dirPath = dirPathBuffer;
for (ndirs = 0; ndirs < MAX_DIRS; ndirs++) {
dirs[ndirs] = dirPath;
colon = strchr(dirPath, ':');
if (colon != NULL) {
*colon = '\0';
}
if (ndirs == 0) {
nows[0] = LoggerGetLastLife(NULL);
} else {
nows[ndirs] = LoggerGetLastLife(dirPath);
}
if (colon == NULL) {
ndirs++;
break;
}
dirPath = colon + 1;
}
}
loss = 0;
overflow = 0;
for (i=iarg; i<argc; i++) {
startim = from;
t = 0;
lastt = 0;
inRange = 0;
xs = step;
InitCompressor(&c, pCon, step);
/* convert slashes to dots */
varp = argv[i];
if (*varp == '/') varp++;
for (j = 0; j < sizeof(var)-1 && *varp != 0; j++, varp++) {
if (*varp == '/') {
var[j] = '.';
} else {
var[j] = *varp;
}
}
c.header = argv[i];
c.period = 0;
var[j] = '\0';
c.type = type0;
c.np = np;
tm = *localtime(&from);
pathLen = 0;
for (idir = 0; idir < ndirs; idir++) {
pathLen = LoggerVarPath(dirs[idir], path, sizeof path, var, &tm);
dr = opendir(path);
if (dr) {
nowi = nows[idir];
closedir(dr);
break;
}
}
isdst = -1;
fil = NULL;
while (startim <= to && c.last.t <= to) {
tm = *localtime(&startim);
if (tm.tm_yday != yday) {
if (fil != NULL) { /* close file if day changed */
fclose(fil);
fil=NULL;
}
}
if (fil == NULL) {
yday = tm.tm_yday;
strftime(path + pathLen, sizeof path - pathLen, "%m-%d.log", &tm);
fil = fopen(path, "r");
if (fil != NULL) { /* check if file is from the given year */
strftime(stim, sizeof stim, "#%Y-%m-%d", &tm);
fgets(line, sizeof line, fil);
if (0 != strncmp(line, stim, 11)) {
fclose(fil);
fil = NULL;
} else {
c.period = getOpt(line, &isdst, &c.exact);
/* if (c.exact) c.period = 0; */
if (c.period >= 0) {
if (c.period == 0) {
c.type = TEXT;
} else {
c.type = type0;
xs = c.period;
}
if (xs < step) {
loss = 1;
xs = step;
}
}
}
}
}
if (fil == NULL) {
lin = NULL;
} else {
do {
lin = fgets(line, sizeof line, fil);
/* printf("%s\n", line); */
if (lin == NULL) break;
if (line[0] == '#') {
c.period = getOpt(line, &isdst, &c.exact);
if (c.period >= 0) {
if (c.period == 0) {
c.type = TEXT;
} else {
c.type = type0;
xs = c.period;
}
if (xs < step) {
loss = 1;
xs = step;
}
}
lin[0]='\0';
} else {
p = strchr(line, '\n'); if (p) *p='\0';
p = strchr(line, '#'); if (p) *p='\0';
}
} while (lin[0] == '\0');
}
if (lin != NULL) {
/* printf(" %s\n", line); */
p = strchr(line, '\t');
if (p) {
*p='\0';
val = p+1;
} else {
val = "";
}
p = strchr(val, '\t');
if (p) {
stp = p+1;
*p='\0';
iret = sscanf(stp, "%ld", &c.period);
if (iret == 1) {
if (c.period == 0) {
c.type = TEXT;
} else {
c.type = type0;
xs = c.period;
}
if (xs < step) {
loss = 1;
xs = step;
}
}
}
iret = sscanf(line, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
if (iret != 3) {
lin = NULL;
} else {
tm.tm_isdst = isdst;
t=mktime(&tm);
if (!inRange) {
if (t < startim) {
lastval[0]='\0';
strncat(lastval, val, sizeof lastval - 1);
lastt = t;
} else {
inRange=1;
if (lastt != 0) {
PutValue(&c, lastt, lastval);
}
PutValue(&c, t, val);
}
} else {
PutValue(&c, t, val);
}
}
}
if (lin == NULL) {
tm.tm_hour = 24; /* try next day */
tm.tm_min = 0;
tm.tm_sec = 0;
tm.tm_isdst = -1;
startim=mktime(&tm);
continue;
}
}
if (!inRange) {
if (lastt != 0) {
PutValue(&c, lastt, lastval);
}
}
WriteHeader(&c); /* write header, if not already done */
PutFinish(&c, nowi);
if (fil) {
fclose(fil);
fil = NULL;
}
if (c.np < 0) overflow = 1;
}
snprintf(line, sizeof line, "*%d %d\n", loss, overflow);
SCWrite(pCon, line, eWarning);
return 1;
illarg:
SCWrite(pCon, "illegal argument(s)", eError);
return 0;
}
/*--------------------------------------------------------------------------*/
static void KillLogReader(void *data) {
Logger *p, *next;
KillDummy(data);
LoggerFreeAll();
}
/*--------------------------------------------------------------------------*/
void LogReaderInit(void) {
AddCommand(pServ->pSics,"Graph",LogReader,KillLogReader,NULL);
}

113
logsetup.c Normal file
View File

@ -0,0 +1,113 @@
#include "logger.h"
#include "sics.h"
#include "sicshipadaba.h"
static char *loggerID = "loggerID";
static hdbCallbackReturn LoggerUpdateCallback(pHdb node,
void *userData, pHdbMessage message) {
Logger *logger = userData;
pDynString str;
SConnection *conn = NULL;
hdbValue value;
pHdbDataMessage mm = NULL;
pHdbDataSearch dsm = NULL;
if ((dsm = GetHdbDataSearchMessage(message)) != NULL) {
if (dsm->testPtr == loggerID) {
dsm->result = userData;
return hdbAbort;
}
return hdbContinue;
}
if((mm = GetHdbUpdateMessage(message)) == NULL){
return hdbContinue;
}
value = *(mm->v);
str = formatValue(value, node);
LoggerWrite(logger, time(NULL), LoggerPeriod(logger), GetCharArray(str));
DeleteDynString(str);
return hdbContinue;
}
static int LogSetup(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]) {
pHdb node;
pHdbCallback cb;
static char basepath[1024]="/";
char buf[1024];
char *p, *name;
static char *loggerDir=NULL;
int numeric, period;
Logger *logger;
if (argc < 2) {
SCPrintf(pCon, eError, "ERROR: should be: logsetup <node> [<period> [<filename>]]");
return 0;
}
if (strcasecmp(argv[1], "basepath") == 0) {
if (argc > 2) {
snprintf(basepath, sizeof basepath, "%s", argv[2]);
}
SCPrintf(pCon, eValue, "%s", basepath);
return 1;
}
if (loggerDir == NULL) {
loggerDir = IFindOption(pSICSOptions, "LoggerDir");
if (loggerDir == NULL) loggerDir="./";
LoggerSetDir(loggerDir);
}
if (strcasecmp(argv[1], "directory") == 0) {
if (argc > 2) {
loggerDir = strdup(argv[2]);
}
SCPrintf(pCon, eValue, "%s", loggerDir);
return 1;
}
node = FindHdbNode(basepath, argv[1], pCon);
if (node == NULL) {
SCPrintf(pCon, eError, "ERROR: %s not found", argv[1]);
return 0;
}
period = 0;
if (argc > 2) {
period = atoi(argv[2]);
}
if (argc > 3) {
snprintf(buf, sizeof buf, "%s", argv[3]);
} else {
snprintf(buf, sizeof buf, "%s", argv[1]);
}
for (p = buf; *p != '\0'; p++) {
if (*p =='/') *p = '.';
}
if (buf[0] == '.') {
name = buf+1;
} else {
name = buf;
}
if (node->value.dataType == HIPFLOAT) {
numeric = 1;
} else {
numeric = 0;
}
logger = FindHdbCallbackData(node, loggerID);
if (logger != 0) { /* logger exists already, changed only period */
LoggerSetPeriod(logger, period);
} else {
logger = LoggerMake(name, period, !numeric);
LoggerSetNumeric(logger, numeric);
cb = MakeHipadabaCallback(LoggerUpdateCallback, logger, (void (*)(void *))LoggerKill);
assert(cb);
AppendHipadabaCallback(node, cb);
}
return 1;
}
void LogSetupInit(void) {
AddCmd("LogSetup",LogSetup);
}

13
macosx_def Normal file
View File

@ -0,0 +1,13 @@
#--------------------------------------------------------------------------
# general defines used within the PSI makefile hierarchy
#
# Mark Koennecke, July 2003
#-------------------------------------------------------------------------
#DFORTIFY= -DFORTIFY
#FORTIFYOBJ= fortify.o strdup.o
#DFORTIFY= -pg
MFLAGS=-f makefile_linux$(DUMMY)
HDFROOT=/Users/Shared

10
macro.c
View File

@ -70,6 +70,7 @@
#include "servlog.h"
#include "stringdict.h"
#include "exeman.h"
#include "nxcopy.h"
#define SICSERROR "005567SICS"
/*----------------------------------------------------------------------------
@ -301,7 +302,8 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp,
/*--------------------------------------------------------------------------
initialises a Tcl-Interpreter, installs SICS unknown mechanism and kills
a few dangerous commands from the normal Tcl command set
*/
----------------------------------------------------------------------------*/
extern int Nxinter_SafeInit(Tcl_Interp *pTcl); /* from Swig NeXus Tcl interface */
Tcl_Interp *MacroInit(SicsInterp *pSics)
{
@ -345,6 +347,9 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp,
*/
Tcl_CreateObjCommand(pInter,"exec",ProtectedExec,NULL,KillExec);
Nxinter_SafeInit(pInter);
NXcopy_Init(pInter);
return pInter;
}
/*--------------------------------------------------------------------------*/
@ -1054,6 +1059,7 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp,
return 0;
}
/* try convert last parameter to user code */
iUser = decodeSICSPriv(argv[2]);
if(iUser < 0)
@ -1069,7 +1075,7 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp,
if (pNew)
{ /* yes -> overwrite access code */
pNew->iUser = iUser;
return 0;
return 1;
}
/* do a job !*/
pNew = CreatePublish(argv[1],iUser);

View File

@ -11,7 +11,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
sicsexit.o costa.o task.o $(FORTIFYOBJ) access.o\
macro.o ofac.o obpar.o obdes.o drive.o status.o intserv.o \
devexec.o mumo.o mumoconf.o selector.o selvar.o fupa.o lld.o \
lld_blob.o strrepl.o lin2ang.o fomerge.o napi4.o napi5.o \
lld_blob.o strrepl.o lin2ang.o fomerge.o napi5.o napi4.o\
script.o o2t.o alias.o napi.o nxdata.o stringdict.o sdynar.o \
histmem.o histdriv.o histsim.o interface.o callback.o nxio.o \
event.o emon.o evcontroller.o evdriver.o simev.o perfmon.o \
@ -31,8 +31,13 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
hmdata.o nxscript.o tclintimpl.o sicsdata.o mcstascounter.o \
mcstashm.o initializer.o remob.o tclmotdriv.o protocol.o \
sinfox.o sicslist.o cone.o hipadaba.o sicshipadaba.o statistics.o \
moregress.o hdbcommand.o multicounter.o regresscter.o histregress.o \
sicshdbadapter.o polldriv.o sicspoll.o statemon.o hmslave.o
ascon.o errormsg.o scriptcontext.o logger.o logreader.o logsetup.o \
savehdb.o statusfile.o sicshdbfactory.o proxy.o devser.o \
moregress.o multicounter.o regresscter.o histregress.o \
sicshdbadapter.o polldriv.o sicspoll.o statemon.o hmslave.o \
nwatch.o asyncqueue.o asyncprotocol.o sicsobj.o \
nxcopy.o nxinterhelper.o nxinter_wrap.o genericcontroller.o nxstack.o \
sctdriveadapter.o sctdriveobj.o
MOTOROBJ = motor.o simdriv.o
COUNTEROBJ = countdriv.o simcter.o counter.o
@ -55,7 +60,7 @@ full: purge all
SICServer: $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) \
$(VELOOBJ) $(DIFIL) $(EXTRA) \
$(SUBLIBS)
$(CC) -g -o SICServer \
$(CC) -g -pg -o SICServer \
$(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) \
$(VELOOBJ) $(DIFOBJ) $(EXTRA) $(LIBS)

42
makefile_macosx Normal file
View File

@ -0,0 +1,42 @@
#---------------------------------------------------------------------------
# Makefile for SICS
# machine-dependent part for Mac OS X
#
# Mark Koennecke 1996-2001
# Markus Zolliker, March 2003
# Mark Koennecke, July 2008
#==========================================================================
# assign if the National Instrument GPIB driver is available
SINQDIR=/Users/Shared
#NI= -DHAVENI
#NIOBJ= nigpib.o
#NILIB=$(SINQDIR)/sl5/lib/cib.o
include macosx_def
CC = gcc
CFLAGS = -I$(HDFROOT)/include -I/sw/include -DNXXML -DHDF5 -DHDF4 $(NI) -DMACOSX \
-Ipsi/hardsup -I. \
-Werror -DNONINTF -g $(DFORTIFY) \
-Wall -Wno-unused -Wno-comment -Wno-switch
BINTARGET = bin
EXTRA=nintf.o
SUBLIBS = psi/libpsi.a psi/hardsup/libhlib.a matrix/libmatrix.a \
psi/tecs/libtecsl.a
LIBS = -L$(HDFROOT)/lib -L/sw/lib $(SUBLIBS) $(NILIB)\
-ltcl $(HDFROOT)/lib/libhdf5.a -lmfhdf -ldf \
$(HDFROOT)/lib/libsz.a \
$(HDFROOT)/lib/libjson.a -ljpeg \
-ldl -lz -lmxml $(HDFROOT)/lib/libghttp.a -lm -lc
include make_gen

View File

@ -9,12 +9,12 @@
SINQDIR=/afs/psi.ch/project/sinq
NI= -DHAVENI
NIOBJ= nigpib.o
NILIB=$(SINQDIR)/sl-linux/lib/cib.o
NILIB=$(SINQDIR)/sl5/lib/cib.o
include sllinux_def
CC = gcc
CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 -DNXXML $(NI) \
CFLAGS = -I$(HDFROOT)/include -DNXXML -DHDF4 -DHDF5 $(NI) \
-Ipsi/hardsup -I. \
-Werror -DCYGNUS -DNONINTF -g $(DFORTIFY) \
-Wall -Wno-unused -Wno-comment -Wno-switch
@ -24,10 +24,11 @@ EXTRA=nintf.o
SUBLIBS = psi/libpsi.a psi/hardsup/libhlib.a matrix/libmatrix.a \
psi/tecs/libtecsl.a
LIBS = -L$(HDFROOT)/lib $(SUBLIBS) $(NILIB)\
-ltcl8.3 $(HDFROOT)/lib/libhdf5.a \
-ltcl $(HDFROOT)/lib/libhdf5.a \
$(HDFROOT)/lib/libmfhdf.a $(HDFROOT)/lib/libdf.a \
$(HDFROOT)/lib/libjpeg.a -lsz $(HDFROOT)/lib/libjson.a \
-ldl -lz -lmxml -lghttp -lm -lc
$(HDFROOT)/lib/libjpeg.a $(HDFROOT)/lib/libsz.a \
$(HDFROOT)/lib/libjson.a \
-ldl -lz -lmxml $(HDFROOT)/lib/libghttp.a -lm -lc
include make_gen

View File

@ -20,7 +20,7 @@
#ifdef __TURBOC__
#include <alloc.h>
#else
#include <malloc.h>
#include <stdlib.h>
#endif
#include "matrix.h"

View File

@ -19,7 +19,7 @@
#ifdef __TURBOC__
#include <alloc.h>
#else
#include <malloc.h>
#include <stdlib.h>
#endif
#include "matrix.h"

View File

@ -20,7 +20,7 @@
#ifdef __TURBOC__
#include <alloc.h>
#else
#include <malloc.h>
#include <stdlib.h>
#endif
#include "matrix.h"

View File

@ -20,7 +20,7 @@
#ifdef __TURBOC__
#include <alloc.h>
#else
#include <malloc.h>
#include <stdlib.h>
#endif
#include "matrix.h"

116
mclist.c Normal file
View File

@ -0,0 +1,116 @@
#ifndef MC_List_TYPE
#define MC_List_TYPE MC_NAME(List)
#define MC_First_FUN MC_NAME(First)
#define MC_This_FUN MC_NAME(This)
#define MC_Next_FUN MC_NAME(Next)
#define MC_End_FUN MC_NAME(End)
#define MC_Insert_FUN MC_NAME(Insert)
#define MC_Add_FUN MC_NAME(Add)
#define MC_Take_FUN MC_NAME(Take)
#endif
#ifdef MC_IMPLEMENTATION
#undef MC_IMPLEMENTATION
#ifndef MC_TYPE
#define MC_TYPE MC_NAME()*
#endif
#else
#define MC_DO_NOT_UNDEF
#include "mclist.h"
#undef MC_DO_NOT_UNDEF
#endif
#ifndef MC_NEXT
#define MC_NEXT next
#endif
MC_TYPE MC_First_FUN(MC_List_TYPE *list) {
list->ptr = &list->head;
return list->head;
}
MC_TYPE MC_This_FUN(MC_List_TYPE *list) {
if (list->head == NULL) {
list->ptr = &list->head;
return NULL;
}
return *list->ptr;
}
MC_TYPE MC_Next_FUN(MC_List_TYPE *list) {
MC_TYPE node;
if (list->head == NULL) {
list->ptr = &list->head;
return NULL;
}
node = *list->ptr;
if (node) {
list->ptr = &node->MC_NEXT;
}
return *list->ptr;
}
void MC_End_FUN(MC_List_TYPE *list) {
MC_TYPE node;
if (list->head == NULL) {
list->ptr = &list->head;
}
node = *list->ptr;
if (node) {
while (node->MC_NEXT != NULL) {
node = node->MC_NEXT;
}
list->ptr = &node->MC_NEXT;
}
}
void MC_Insert_FUN(MC_List_TYPE *list, MC_TYPE node) {
if (list->head == NULL) {
list->ptr = &list->head;
}
node->MC_NEXT = *list->ptr;
*list->ptr = node;
}
void MC_Add_FUN(MC_List_TYPE *list, MC_TYPE node) {
node->MC_NEXT = NULL;
if (list->head == NULL) {
list->head = node;
list->ptr = &list->head;
} else {
if (*list->ptr != NULL) {
MC_End_FUN(list);
}
*list->ptr = node;
}
}
MC_TYPE MC_Take_FUN(MC_List_TYPE *list) {
MC_TYPE node;
node = *list->ptr;
if (node != NULL) {
*list->ptr = node->MC_NEXT;
}
return node;
}
void MC_Delete_FUN(MC_List_TYPE *list, void (*deleteFunc)(MC_TYPE n)) {
MC_TYPE node;
MC_TYPE victim;
node = list->head;
while (node != NULL) {
victim = node;
node = node->next;
deleteFunc(victim);
}
list->head = NULL;
list->ptr = &list->head;
}
#undef MC_NAME
#undef MC_TYPE
#undef MC_NEXT

177
mclist.h Normal file
View File

@ -0,0 +1,177 @@
/** \file
* \brief Type safe list handling
*
* The definition and implementation make use of macros extensively to create
* a list type and related functions for any node type.
* <b>However, accessing the list does not use macros.</b>
* The list is implemented as a singly linked list. Sequential appending
* to the tail is fast, because the list structure contains
* a pointer to the anchor of the last accessed node.
*
* For a local list, mclist.c must be included after
* the declaration of the node type and after defining the macro MC_NAME
* and optionally MC_TYPE and MC_NEXT.
*
* For a public list, in the header file mclist.h must be included after
* the declaration of the node type and after defining the macro MC_NAME
* and optionally MC_TYPE. In the implementation mclist.c
* must be included after defining the macro MC_NAME and MC_IMPLEMENTATION
* and optionally MC_TYPE and MC_NEXT.
*
* MC_NAME has one parameter and describes how to combine the list name
* with the function names.
*
* MC_TYPE defines the node type. If undeclared it defaults to a pointer
* to the name.
*
* MC_NEXT indicates the name of the link. It defaults to 'next'.
*
* MC_IMPLEMENTATION has no value and must be defined when the list type
* was already declared. Typically this is done in a header file including mclist.h.
*
* The macros MC_NAME, MC_TYPE, MC_NEXT and MC_IMPLEMENTATION are undefined
* within mclist.c and mclist.h and must be redefined for every list.
*
* \par Usage example
* \code
* // declare the Node type
* typedef struct Node {
* struct Node *next;
* char *name;
* } Node;
*
* // this declaration leads to a list type 'NodeList' and fucntions names 'Node<fun>'
* #define MC_NAME(T) Node##T
* // the following line is not needed as 'next' is the default for the link
* #define MC_NEXT next
* // the following line is not needed as 'Node *' is the default for the type in this case
* #define MC_TYPE Node *
* // inside mclist.c, the list type is declared and the related functions are implemented
* #include "mclist.c"
*
* int main(void) {
* // declare and init the list
* NodeList list={NULL};
*
* // create a node
* Node *node;
* node = malloc(sizeof(*node));
* node->name = "First";
*
* // add node at the end of the list
* NodeAdd(&list, node);
*
* // print the names of all list nodes
* for (node = NodeFirst(&list); node != NULL; node = NodeNext(&list)) {
* printf("%s\n", node->name);
* }
*
* // alternative form not touching the list position
* // only for the case, where no insert or take function is used inside the loop
* for (node = list.head; node != NULL; node = node->next) {
* printf("%s\n", node->name);
* }
*
* // remove the node with the name "First"
* for (node = NodeFirst(&list); node != NULL; node = NodeNext(&list)) {
* if (strcmp(node->name, "First") == 0) {
* free(NodeTake(&list));
* }
* }
* }
* \endcode
*/
#ifndef MC_TYPE
/** \brief default node type
*/
#define MC_TYPE MC_NAME()*
#endif
#ifndef MC_List_TYPE
#define MC_List_TYPE MC_NAME(List)
#define MC_First_FUN MC_NAME(First)
#define MC_This_FUN MC_NAME(This)
#define MC_Next_FUN MC_NAME(Next)
#define MC_End_FUN MC_NAME(End)
#define MC_Insert_FUN MC_NAME(Insert)
#define MC_Add_FUN MC_NAME(Add)
#define MC_Take_FUN MC_NAME(Take)
#define MC_Delete_FUN MC_NAME(Delete)
#endif
typedef struct MC_List_TYPE {
MC_TYPE head;
MC_TYPE *ptr;
} MC_List_TYPE;
/** \brief move to first node and get it
* \param list the list
* \return the node or NULL when the list is empty
*
* Actual position on return: at the first node
*/
MC_TYPE MC_First_FUN(MC_List_TYPE *list);
/** \brief get the node at the current position
* \param list the list
* \return the node or NULL when the list is empty or the position is at end
*
* Actual position on return: not changed (= at the returned node)
*/
MC_TYPE MC_This_FUN(MC_List_TYPE *list);
/** \brief get the node after the current node
* \param list the list
* \return the node or NULL when the list is empty or the position is at end
*
* Actual position on return: incremented (= at the returned node or at end)
*/
MC_TYPE MC_Next_FUN(MC_List_TYPE *list);
/** \brief move the position to the end
* \param list the list
*
* Actual position on return: at end
*/
void MC_End_FUN(MC_List_TYPE *list);
/** \brief insert at the current position, i.e. before the current node
* \param list the list
* \param node the node to be inserted
*
* Actual position on return: at the inserted node
*/
void MC_Insert_FUN(MC_List_TYPE *list, MC_TYPE node);
/** \brief add at the end of the list
* \param list the list
* \param node the node to be added
*
* Actual position on return: at the inserted node (before the last node, not at end!)
*/
void MC_Add_FUN(MC_List_TYPE *list, MC_TYPE node);
/** \brief remove the node at the current position
* \param list the list
* \return the removed node or NULL when the list is empty or the position is at end
*
* Actual position on return: after the taken node
*
* Note: it is the responsibility of the caller to free the node if it is not used
* anymore
*/
MC_TYPE MC_Take_FUN(MC_List_TYPE *list);
/** \brief remove and delete all nodes
* \param list the list
* \param deleteFunc the kill function of the node
*
* Calls the kill function for every node. The list is
* empty on return.
*/
void MC_Delete_FUN(MC_List_TYPE *list, void (*deleteFunc)(MC_TYPE node));
#ifndef MC_DO_NOT_UNDEF
#undef MC_NAME
#undef MC_TYPE
#endif

View File

@ -178,6 +178,7 @@ static int insertMonitor(pMcStasReader self, SConnection *pCon,
return 0;
}
memset(pBueffel,0,512);
status = NXgetdata(self->handle,pBueffel);
if(status != NX_OK){
snprintf(pBueffel,511,"ERROR: Nexus error %s while reading %s",

View File

@ -1,3 +1,3 @@
133
230
NEVER, EVER modify or delete this file
You'll risk eternal damnation and a reincarnation as a cockroach!|n

174
mcstas/dmc/gumibatch.tcl Normal file
View File

@ -0,0 +1,174 @@
#-------------------------------------------------------------
# This is a set of Tcl procedures which try to convert an old
# batch file into a batch file suitable for Mountaingum.
#
# copyright: GPL
#
# Mark Koennecke, February 2008
#-------------------------------------------------------------
if {[string first tmp $home] < 0} {
set tmppath $home/tmp
} else {
set tmppath $home
}
#-------------------------------------------------------------
proc searchPathForDrivable {name} {
set path [string trim [hmatchprop / sicsdev $name]]
if {[string compare $path NONE] != 0} {
return $path
}
set txt [findalias $name]
if {[string compare $txt NONE] == 0} {
return NONE
}
set l1 [split $txt =]
set l [split [lindex $l1 1] ,]
foreach alias $l {
set alias [string trim $alias]
set path [string trim [hmatchprop / sicsdev $alias]]
if {[string compare $path NONE] != 0} {
return $path
}
}
return NONE
}
#----------------------------------------------------------------
proc searchForCommand {name} {
return [string trim [hmatchprop / sicscommand $name]]
}
#----------------------------------------------------------------
proc treatsscan {scanpath command out} {
set l [split $command]
set len [llength $l]
set noVar [expr ($len-2)/3]
set np [lindex $l [expr $len -2]]
set preset [lindex $l [expr $len -1]]
for {set i 0} {$i < $noVar} {incr i} {
set start [expr $i * 3]
set scanVar [lindex $l [expr 1 + $start]]
set scanStart [lindex $l [expr 2 + $start]]
set scanEnd [lindex $l [expr 3 + $start]]
set scanStep [expr ($scanEnd*1. - $scanStart*1.)/$np*1.]
append hdbVar $scanVar ,
append hdbStart $scanStart ,
append hdbStep $scanStep ,
}
set hdbVar [string trim $hdbVar ,]
set hdbStart [string trim $hdbStart ,]
set hdbStep [string trim $hdbStep ,]
puts $out "\#NODE: $scanpath"
puts $out "clientput BatchPos = 1"
puts $out "hdbscan $hdbVar $hdbStart $hdbStep $np monitor $preset"
}
#----------------------------------------------------------------
proc treatcscan {scanpath command out} {
set l [split $command]
set scanVar [lindex $l 1]
set scanCenter [lindex $l 2]
set scanStep [lindex $l 3]
set np [lindex $l 4]
set preset [lindex $l 5]
set hdbStart [expr $scanCenter - ($np*1.0)/2. * $scanStep*1.0]
puts $out "\#NODE: $scanpath"
puts $out "clientput BatchPos = 1"
puts $out "hdbscan $scanVar $hdbStart $scanStep $np monitor $preset"
}
#----------------------------------------------------------------
proc translateCommand {command out} {
set drivelist [list drive dr run]
set textList [list for while source if]
# clientput "Translating: $command"
set command [string trim $command]
if {[string length $command] < 2} {
return
}
set l [split $command]
set obj [string trim [lindex $l 0]]
#------- check for drive commands
set idx [lsearch $drivelist $obj]
if {$idx >= 0} {
set dev [lindex $l 1]
set path [searchPathForDrivable $dev]
if {[string compare $path NONE] != 0} {
set realTxt [hgetprop $path sicsdev]
set realL [split $realTxt =]
set realDev [lindex $realL 1]
set mapList [list $dev $realDev]
set newCom [string map $mapList $command]
puts $out "\#NODE: $path"
puts $out "clientput BatchPos = 1"
puts $out $newCom
return
}
}
#------ check for well known broken commands
set idx [lsearch $textList $obj]
if {$idx >= 0} {
puts $out "\#NODE: /batch/commandtext"
puts $out "clientput BatchPos = 1"
set buffer [string map {\n @nl@} $command]
puts $out "hset /batch/commandtext $buffer"
return
}
#--------- check for simple commands
set path [searchForCommand $command]
if {[string compare $path NONE] != 0} {
puts $out "\#NODE: $path"
puts $out "clientput BatchPos = 1"
puts $out $command
return
}
set scancom [searchForCommand hdbscan]
#---------- deal with scans
if {[string first sscan $obj] >= 0} {
if {[catch {treatsscan $scancom $command $out}] == 0} {
return
}
}
if {[string first cscan $obj] >= 0} {
if {[catch {treatsscan $scancom $command $out}] == 0} {
return
}
}
#--------- give up: output as a text node
puts $out "\#NODE: /batch/commandtext"
puts $out "clientput BatchPos = 1"
set buffer [string map {\n @nl@} $command]
puts $out "hset /batch/commandtext $buffer"
}
#----------------------------------------------------------------
proc mgbatch {filename} {
global tmppath
set f [open $filename r]
gets $f line
close $f
if {[string first MOUNTAINBATCH $line] > 0} {
#--------- This is a mountaingum batch file which does not need
# to be massaged
return $filename
}
set f [open $filename r]
set realfilename [file tail $filename]
set out [open $tmppath/$realfilename w]
puts $out \#MOUNTAINBATCH
while {[gets $f line] >= 0} {
append buffer $line
if {[info complete $buffer] == 1} {
translateCommand $buffer $out
unset buffer
} else {
append buffer \n
}
}
close $out
return $tmppath/$realfilename
}
#----------------------------------------------------------------
proc loadmgbatch {filename} {
set txt [exe fullpath $filename]
set l [split $txt =]
set realf [lindex $l 1]
set realf [mgbatch $realf]
return [exe print $realf]
}

80
mcstas/dmc/gumxml.tcl Normal file
View File

@ -0,0 +1,80 @@
proc getdataType {path} {
return [lindex [split [hinfo $path] ,] 0]
}
proc make_nodes {path result indent} {
set nodename [file tail $path];
set type [getdataType $path]
set prefix [string repeat " " $indent]
set newIndent [expr $indent + 2]
#array set prop_list [ string trim [join [split [hlistprop $path] =]] ]
set prop_list(control) true
set we_have_control [info exists prop_list(control)]
if {$we_have_control == 0 || $we_have_control && $prop_list(control) == "true"} {
append result "$prefix<component id=\"$nodename\" dataType=\"$type\">\n"
foreach p [property_elements $path $newIndent] {
append result $p
}
foreach x [hlist $path] {
set result [make_nodes [string map {// /} "$path/$x"] $result $newIndent]
}
append result "$prefix</component>\n"
}
return $result
}
proc property_elements_old {path indent} {
set prefix [string repeat " " $indent]
foreach {key value} [string map {= " "} [hlistprop $path]] {
if {[string compare -nocase $key "control"] == 0} {continue}
lappend proplist "$prefix<property id=\"$key\">\n"
# foreach v [split $value ,] {
# lappend proplist "$prefix$prefix<value>$v</value>\n"
# }
lappend proplist "$prefix$prefix<value>$value</value>\n"
lappend proplist "$prefix</property>\n"
}
if [info exists proplist] {return $proplist}
}
proc property_elements {path indent} {
set prefix [string repeat " " $indent]
set data [hlistprop $path]
set propList [split $data \n]
foreach prop $propList {
set pl [split $prop =]
set key [string trim [lindex $pl 0]]
set value [string trim [lindex $pl 1]]
if {[string length $key] < 1} {
continue
}
lappend proplist "$prefix<property id=\"$key\">\n"
lappend proplist "$prefix$prefix<value>$value</value>\n"
lappend proplist "$prefix</property>\n"
}
if [info exists proplist] {return $proplist}
}
proc getgumtreexml {path} {
append result "<?xml version = \"1.0\" encoding = \"UTF-8\"?>\n"
append result "<hipadaba:SICS xmlns:hipadaba=\"http://www.psi.ch/sics/hipadaba\" >\n"
if {[string compare $path "/" ] == 0} {
foreach n [hlist $path] {
set result [make_nodes $n $result 2]
}
} else {
# set result [make_nodes $path $result 2]
foreach n [hlist $path] {
set result [make_nodes $path/$n $result 2]
}
}
append result "</hipadaba:SICS>\n"
}
if {[info exists guminit] == 0} {
set guminit 1
Publish getgumtreexml Spy
}

View File

@ -30,7 +30,7 @@ proc washsimfile {name} {
# dump its data. Otherwise we observe that data reading fails.
# mcwaittime is used for this. Increase if you see problems
#--------------------------------------------------------------------
set mcwaittime 7
set mcwaittime 2
#----------------------------------------------------------------------
proc mcstasdump {pid} {
global mcwaittime

View File

@ -12,6 +12,7 @@ if {$wwwMode == 1} {
set datahome /home/lnswww/www/vinstrument
} else {
set home $env(HOME)/src/workspace/sics/mcstas/dmc
ServerOption LoggerDir $env(HOME)/src/workspace/sics/mcstas/dmc/samenv
}
#--------------------------------- first all the server options are set
#ServerOption RedirectFile $home/stdcdmc
@ -31,21 +32,22 @@ SicsUser lnsmanager lnsSICSlns 1
SicsUser Manager Manager 1
SicsUser user looser 2
SicsUser Spy 007 1
SicsUser User 07lns1 2
#--------------------------------------------------------------------------
# D E V I C E S : M O T O R S
#---------------------------------------------------------------------------
ClientPut "Installing Motors"
Motor OmegaM SIM 0 120 -.1 2.
Motor TwoThetaM SIM 30 100 -.1 1.
Motor MonoX SIM -30 30 -.1 3.0
Motor MonoY SIM -30 30 -.1 3.0
Motor CurveM SIM 0 20 -.1 3.0
Motor MonoPhi SIM -30 30 -.1 3.0
Motor MonoChi SIM -30 30 -.1 3.0
Motor OmegaM SIM 0 120 .0000001 2.
Motor TwoThetaM SIM 30 100 .0000001 1.
Motor MonoX SIM -30 30 .00000001 3.0
Motor MonoY SIM -30 30 .000000001 3.0
Motor CurveM SIM 0 20 .000000001 3.0
Motor MonoPhi SIM -30 30 .00000001 3.0
Motor MonoChi SIM -30 30 .00000001 3.0
# sample Table
Motor Table SIM -180 360 -.1 2.
Motor TwoThetaD SIM -10 120 -.1 1.
Motor Table SIM -180 360 .0000001 2.
Motor TwoThetaD SIM -10 120 .0000001 1.
#-------------------------------------------------------------
# Monochromator
#-------------------------------------------------------------
@ -66,6 +68,7 @@ allowexec $home/dmcafter
allowexec $home/dmc_sics05
ClientPut "Installing counter"
MakeCounter counter mcstas
counter SetExponent 1
MakeHM banana mcstas
@ -79,7 +82,7 @@ banana CountMode Timer
banana configure Counter counter
banana configure init 0
banana init
banana exponent 3
#banana exponent 3
#-------------------------------------------------------------------------
# Aliases
#-------------------------------------------------------------------------
@ -122,6 +125,7 @@ VarMake starttime Text User
starttime ""
VarMake SicsDataPrefix Text Internal
SicsDataPrefix vdmc
#--------- make data number
MakeDataNumber SicsDataNumber $home/DataNumber
VarMake SicsDataPostFix Text Internal
@ -132,6 +136,8 @@ VarMake fax Text User
VarMake email Text User
VarMake sample_mur Float User
VarMake lastdatafile Text User
VarMake lastscancommand Text User
lastscancommand "unknown scan"
#--------------------------------------------------------------------------
# P R O C E D U R E S
#--------------------------------------------------------------------------
@ -139,21 +145,44 @@ MakeDrive
MakeBatchManager
MakeNXScript
MakeRuenBuffer
#------------------------------------------------------------------------
# simulated scanning for demo purposes
#-----------------------------------------------------------------------
MakeCounter lieselotte SIM -1
MakeMultiCounter scanCter lieselotte
#------------------------------
proc SICSValue {command} {
set txt [eval $command]
set l [split $txt =]
return [string trim [lindex $l 1]]
}
#-----------------------------------------------------------------------
proc scantransfer {} {
set FWHM 1.5
set pos 5.33
set height 700
set stddev [expr $FWHM/2.354]
set ftmp [expr ([SICSValue a3] - $pos)/$stddev]
set count [expr 10 + $height*0.4*exp(-.5*$ftmp*$ftmp)]
set counti [expr int($count)]
append res [SICSValue "lieselotte gettime"] " "
append res $counti " "
for {set i 1} {$i < 7} {incr i} {
append res [SICSValue "lieselotte getmonitor $i"] " "
}
return $res
}
scancter transferscript scantransfer
MakeScanCommand xxxscan scancter $home/dmc.hdd $home/recover.bin
MakePeakCenter xxxscan
#-------------------- initialize scripted commands
source $home/vdmccom.tcl
#-------------------- configure commandlog
commandlog auto
commandlog intervall 5
#----------- enable sycamore
#InstallSinfox
#source sycFormat.tcl
#source /usr/lib/tcllib1.6.1/stooop/stooop.tcl
#namespace import stooop::*
#source sinfo.tcl
#source sycamore.tcl
#Publish sinfo Spy
#==================== install Hipadaba
proc hdbReadOnly {} {
error "Parameter is READ ONLY"
@ -169,82 +198,178 @@ proc maketwotheta {} {
return $result
}
#-------------------------------------
InstallProtocolHandler
InstallHdb
MakeStateMon
hmake /dmc spy none
hsetprop /dmc type instrument
MakeHdbQueue hdbqueue HdbQueue
hmake /instrument spy none
hsetprop /instrument type instrument
#-------- experiment
hmake /dmc/experiment spy none
hattach /dmc/experiment title title
hattach /dmc/experiment user user
hattach /dmc/experiment starttime starttime
hattach /dmc/experiment user user
hattach /dmc/experiment/user adress address
hattach /dmc/experiment/user phone phone
hattach /dmc/experiment/user email email
hattach /dmc/experiment comment1 comment1
hattach /dmc/experiment comment2 comment2
hattach /dmc/experiment comment3 comment3
hmake /instrument/experiment spy none
hattach /instrument/experiment title title
hattach /instrument/experiment starttime starttime
hattach /instrument/experiment user user
hattach /instrument/experiment/user adress address
hattach /instrument/experiment/user phone phone
hattach /instrument/experiment/user email email
hattach /instrument/experiment comment1 comment1
hattach /instrument/experiment comment2 comment2
hattach /instrument/experiment comment3 comment3
#------- SINQ
hmake /dmc/sinq spy none
hmakescript /dmc/sinq/proton_monitor "counter getmonitor 4" hdbReadOnly int
sicspoll /dmc/sinq/proton_monitor hdb 10
hmake /instrument/sinq spy none
hmake /instrument/sinq/proton_monitor internal int
hattach /instrument/sinq/proton_monitor counter 4
#-------- monochromator
hmake /dmc/monochromator spy none
hattach /dmc/monochromator lambda wavelength
hattach /dmc/monochromator OmegaM theta
hattach /dmc/monochromator TwoThetaM two_theta
hattach /dmc/monochromator MonoX x_translation
hattach /dmc/monochromator MonoY y_translation
hattach /dmc/monochromator MonoChi chi
hattach /dmc/monochromator MonoPhi phi
hattach /dmc/monochromator CurveM vertical_focusing
hmakescript /dmc/monochromator/d_value "mono dd" "mono dd" float
hsetprop /dmc/monochromator/d_value priv manager
hmakescript /dmc/monochromator/scattering_sense "mono ss" "mono ss" int
hsetprop /dmc/monochromator/scattering_sense priv manager
hmake /instrument/monochromator spy none
hattach /instrument/monochromator lambda wavelength
hsetprop /instrument/monochromator/wavelength priv user
hattach /instrument/monochromator OmegaM theta
hattach /instrument/monochromator TwoThetaM two_theta
hchain /instrument/monochromator/wavelength /instrument/monochromator/two_theta
hattach /instrument/monochromator MonoX x_translation
hattach /instrument/monochromator MonoY y_translation
hattach /instrument/monochromator MonoChi chi
hattach /instrument/monochromator MonoPhi phi
hattach /instrument/monochromator CurveM vertical_focusing
hmakescript /instrument/monochromator/d_value "mono dd" "mono dd" float
hsetprop /instrument/monochromator/d_value priv manager
hmakescript /instrument/monochromator/scattering_sense "mono ss" "mono ss" int
hsetprop /instrument/monochromator/scattering_sense priv manager
#----------- sample
hmake /dmc/sample spy none
hmakescript /dmc/sample/name sample sample Text
hattach /dmc/sample Table rotation
hmakescript /dmc/sample/monitor "counter getmonitor 1" hdbReadOnly int
hsetprop /dmc/sample/monitor priv internal
hmake /instrument/sample spy none
hmakescript /instrument/sample/name sample sample Text
hattach /instrument/sample Table rotation
hmake /instrument/sample/monitor internal int
hattach /instrument/sample/monitor counter 1
hsetprop /instrument/sample/monitor priv internal
hsetprop /instrument/sample/monitor sicsdev histogrammemory
#---------- detector
hmake /dmc/detector spy none
hattach /dmc/detector TwoThetaD two_theta
hmakescript /dmc/detector/preset "counter getpreset" hdbReadOnly float
hsetprop /dmc/detector/preset priv internal
hmakescript /dmc/detector/countmode "counter getmode" hdbReadOnly text
hsetprop /dmc/detector/countmode priv internal
sicspoll add /dmc/detector/preset hdb 30
sicspoll add /dmc/detector/countmode hdb 30
hmake /instrument/detector spy none
hattach /instrument/detector TwoThetaD two_theta
hmakescript /instrument/detector/preset "banana preset" hdbReadOnly float
hsetprop /instrument/detector/preset priv internal
hmakescript /instrument/detector/countmode "banana countmode" hdbReadOnly text
hsetprop /instrument/detector/countmode priv internal
sicspoll add /instrument/detector/preset hdb 30
sicspoll add /instrument/detector/countmode hdb 30
hmake /instrument/detector/count_time internal float
hattach /instrument/detector/count_time counter -1
#------------ commands
hmake /commands spy none
hcommand /commands/count count
hsetprop /commands/count type command
hmake /commands/count/mode user text
hmake /commands/count/preset user float
hset /commands/count/preset 5
hset /commands/count/mode timer
hmake /instrument/commands spy none
hcommand /instrument/commands/count count
hsetprop /instrument/commands/count type command
hsetprop /instrument/commands/count priv user
hmake /instrument/commands/count/mode user text
hsetprop /instrument/commands/count/mode values "monitor,timer"
hmake /instrument/commands/count/preset user float
hset /instrument/commands/count/preset 60000
hset /instrument/commands/count/mode monitor
hcommand /instrument/commands/killfile killfile
hsetprop /instrument/commands/killfile type command
hsetprop /instrument/commands/killfile priv manager
#------------- scan command
hcommand /instrument/commands/scan hdbscan
hsetprop /instrument/commands/scan type command
hsetprop /instrument/commands/scan priv user
hsetprop /instrument/commands/scan viewer mountaingumui.ScanEditor
hmake /instrument/commands/scan/scan_variables user text
hsetprop /instrument/commands/scan/scan_variables argtype drivable
hmake /instrument/commands/scan/scan_start user text
hmake /instrument/commands/scan/scan_increments user text
hmake /instrument/commands/scan/NP user int
hmake /instrument/commands/scan/mode user text
hsetprop /instrument/commands/scan/mode values "timer,monitor"
hmake /instrument/commands/scan/preset user float
hset /instrument/commands/scan/mode timer
hset /instrument/commands/scan/scan_start 2.
hset /instrument/commands/scan/scan_increments .3
hset /instrument/commands/scan/NP 25
hset /instrument/commands/scan/preset 2
hcommand /instrument/commands/wait wait
hsetprop /instrument/commands/wait type command
hsetprop /instrument/commands/wait priv user
hmake /instrument/commands/wait/time user int
#---------------- graphics
hmake /Graphics spy none
hmake /Graphics/powder_diagram spy none
hsetprop /Graphics/powder_diagram type graphdata
hsetprop /Graphics/powder_diagram viewer default
hmake /Graphics/powder_diagram/rank internal int
hset /Graphics/powder_diagram/rank 1
hmake /Graphics/powder_diagram/dim internal intar 1
hset /Graphics/powder_diagram/dim 400
hmakescript /Graphics/powder_diagram/two_theta maketwotheta hdbReadOnly floatar 400
sicspoll add /Graphics/powder_diagram/two_theta hdb 30
hsetprop /Graphics/powder_diagram/two_theta type axis
hsetprop /Graphics/powder_diagram/two_theta dim 0
hattach /Graphics/powder_diagram banana counts
hsetprop /Graphics/powder_diagram/counts type data
hsetprop /Graphics/powder_diagram/counts priv internal
sicspoll add /Graphics/powder_diagram/counts hdb 60
hmake /graphics spy none
hmake /graphics/powder_diagram spy none
hattach /graphics/powder_diagram title title
hsetprop /graphics/powder_diagram type graphdata
hsetprop /graphics/powder_diagram viewer default
hmake /graphics/powder_diagram/rank internal int
hset /graphics/powder_diagram/rank 1
hmake /graphics/powder_diagram/dim internal intar 1
hset /graphics/powder_diagram/dim 400
hmakescript /graphics/powder_diagram/two_theta maketwotheta hdbReadOnly floatar 400
hchain /graphics/powder_diagram/two_theta /instrument/detector/two_theta
hsetprop /graphics/powder_diagram/two_theta type axis
hsetprop /graphics/powder_diagram/two_theta transfer zip
hsetprop /graphics/powder_diagram/two_theta dim 0
hattach /graphics/powder_diagram banana counts
hsetprop /graphics/powder_diagram/counts type data
hsetprop /graphics/powder_diagram/counts transfer zip
hsetprop /graphics/powder_diagram/counts priv internal
sicspoll add /graphics/powder_diagram/counts hdb 60
hmake /graphics/scan_data spy none
hsetprop /graphics/scan_data type graphdata
hsetprop /graphics/scan_data viewer default
hmake /graphics/scan_data/rank mugger int
hset /graphics/scan_data/rank 1
hsetprop /graphics/scan_data/rank priv internal
hmakescript /graphics/scan_data/dim "xxxscan np" hdbReadOnly intar 1
hsetprop /graphics/scan_data/dim priv internal
hmakescript /graphics/scan_data/scan_variable "gethdbscanvardata 0" hdbReadOnly floatvarar 1
hsetprop /graphics/scan_data/scan_variable type axis
hsetprop /graphics/scan_data/scan_variable dim 0
hsetprop /graphics/scan_data/scan_variable transfer zip
hsetprop /graphics/scan_data/scan_variable priv internal
hmakescript /graphics/scan_data/counts "gethdbscancounts" hdbReadOnly intvarar 1
hsetprop /graphics/scan_data/counts type data
hsetprop /graphics/scan_data/counts transfer zip
hsetprop /graphics/scan_data/counts priv internal
hmake /graphics/samenv spy none
hsetprop /graphics/samenv type graphdata
hsetprop /graphics/samenv viewer mountaingumui.TimeSeries
hmake /graphics/samenv/vars user text
hset /graphics/samenv/vars tomato
hmake /graphics/samenv/rank user int
hset /graphics/samenv/rank 1
hmake /graphics/samenv/dim user intar 1
hset /graphics/samenv/dim 300
hmake /graphics/samenv/getdata user text
hsetprop /graphics/samenv/getdata type logcommand
hsetprop /graphics/samenv/getdata datacom true
hmake /graphics/samenv/getdata/starttime spy text
hmake /graphics/samenv/getdata/endtime spy text
hmake /batch spy none
hmakescript /batch/bufferlist listbatchfiles hdbReadOnly text
sicspoll add /batch/bufferlist hdb 30
hmake /batch/commandtext spy text
hsetprop /batch/commandtext viewer mountaingumui.TextEdit
hsetprop /batch/commandtext commandtext true
hmake /gui spy none
hmake /gui/status internal text
status hdbinterest /gui/status
proc makeQuickPar {name path} {
hmake /quickview/$name mugger text
hset /quickview/$name $path
}
hmake /quickview spy none
makeQuickPar title /instrument/experiment/title
makeQuickPar sample /instrument/sample/name
makeQuickPar lambda /instrument/monochromator/wavelength
makeQuickPar two-theta /instrument/detector/two_theta
makeQuickPar preset /instrument/detector/preset
makeQuickPar monitor /instrument/sample/monitor
restore

View File

@ -18,10 +18,18 @@ if { [info exists vdmcinit] == 0 } {
Publish wwwfilefornumber Spy
mcinstall
Publish gethm Spy
Publish hdbscan User
Publish hdbprepare User
Publish hdbcollect User
Publish mgbatch Spy
Publish loadmgbatch Spy
Publish listbatchfiles Spy
}
source $home/log.tcl
source $home/nxsupport.tcl
source $home/nxdmc.tcl
source $home/gumxml.tcl
source $home/gumibatch.tcl
#------------------------------------------------------------------------
proc SplitReply { text } {
set l [split $text =]
@ -193,8 +201,17 @@ proc copydmcdataold { } {
proc copydmcdata { } {
global home
set mcversion "McStas 1.8 - Mar. 05, 2004"
#---- loop till the file can be opened
for {set i 0} {$i < 20} {incr i} {
washsimfile $home/dmc.xml
mcreader open $home/dmc.xml
set stat [catch {mcreader open $home/dmc.xml} msg]
if {$stat == 0} {
break
} else {
file copy -force $home/dmc.xml $home/brokenfile.xml
wait 1
}
}
mcreader insertmon \
"/$mcversion/DMC_diff/dmc.xml/PSD_sample/values" \
counter 1 [expr 1./350]
@ -260,6 +277,7 @@ proc count { {mode NULL } { preset NULL } } {
#------- count
banana InitVal 0
wait 1
hupdate /graphics/powder_diagram/counts
banana count
set ret [catch {Success} msg]
#------- StoreData
@ -395,5 +413,92 @@ proc wwwfilefornumber {num} {
proc gethm {} {
banana uuget 0
}
#--------------------------------------------------------------------
proc hdbscan {scanvars scanstart scanincr np mode preset} {
xxxscan clear
xxxscan configure script
xxxscan function prepare hdbprepare
xxxscan function collect hdbcollect
set varlist [split $scanvars ,]
set startlist [split $scanstart ,]
set incrlist [split $scanincr ,]
set count 0
foreach var $varlist {
if {[string first / $var] >= 0} {
set var [string trim [SplitReply [hgetprop $var sicsdev]]]
}
xxxscan add $var [lindex $startlist $count] [lindex $incrlist $count]
incr count
}
set status [catch {xxxscan run $np $mode $preset} msg]
if {$status == 0} {
return $msg
} else {
error $msg
}
}
#------------------------------------------------------------------------------
proc hdbprepare {obj userdata } {
stdscan prepare $obj userdata
hupdate /graphics/scan_data/dim
}
#------------------------------------------------------------------------------
proc hdbcollect {obj userobj np} {
stdscan collect $obj $userobj $np
hupdate /graphics/scan_data/scan_variable
hupdate /graphics/scan_data/counts
}
#-----------------------------------------------------------------------------
proc gethdbscanvardata {no} {
set np [string trim [SplitReply [xxxscan np]]]
if {$np == 0} {
return ".0 .0 .0"
}
set status [catch {SplitReply [xxxscan getvardata $no]} txt]
if {$status == 0} {
return [join $txt]
} else {
return ".0 .0 .0"
}
}
#----------------------------------------------------------------------------
proc gethdbscancounts {} {
set np [string trim [SplitReply [xxxscan np]]]
if {$np == 0} {
return "0 0 0"
}
set status [catch {SplitReply [xxxscan getcounts]} txt]
if {$status == 0} {
return [join $txt]
} else {
return "0 0 0"
}
}
#================= helper to get the list of batch files =================
proc listbatchfiles {} {
set ext [list *.tcl *.job]
set txt [SplitReply [exe batchpath]]
set dirlist [split $txt :]
set txt [SplitReply [exe syspath]]
set dirlist [concat $dirlist [split $txt :]]
set result [list ""]
foreach dir $dirlist {
foreach e $ext {
set status [catch {glob [string trim $dir]/$e} filetxt]
if {$status == 0} {
set filelist [split $filetxt]
foreach f $filelist {
set nam [file tail $f]
if { [lsearch $result $nam] < 0} {
lappend result $nam
}
}
}
}
}
foreach bf $result {
append resulttxt $bf ,
}
return [string trim $resulttxt ,]
}
#-----------------------------------------------------------------------

View File

@ -1,5 +1,9 @@
exe batchpath ./
exe batchpath tmp
exe syspath ./
#--- BEGIN (commands producing errors on last restore)
#--- END (commands producing errors on last restore)
# Motor omegam
omegam sign 1.000000
omegam SoftZero 0.000000
@ -10,17 +14,21 @@ omegam InterruptMode 0.000000
omegam precision 0.010000
omegam ignorefault 0.000000
omegam AccessCode 2.000000
omegam failafter 3.000000
omegam maxretry 3.000000
omegam movecount 10.000000
# Motor twothetam
twothetam sign 1.000000
twothetam SoftZero 0.000000
twothetam SoftLowerLim 30.000000
twothetam SoftLowerLim 35.000000
twothetam SoftUpperLim 100.000000
twothetam Fixed -1.000000
twothetam InterruptMode 0.000000
twothetam precision 0.010000
twothetam ignorefault 0.000000
twothetam AccessCode 2.000000
twothetam failafter 3.000000
twothetam maxretry 3.000000
twothetam movecount 10.000000
# Motor monox
monox sign 1.000000
@ -32,6 +40,8 @@ monox InterruptMode 0.000000
monox precision 0.010000
monox ignorefault 0.000000
monox AccessCode 2.000000
monox failafter 3.000000
monox maxretry 3.000000
monox movecount 10.000000
# Motor monoy
monoy sign 1.000000
@ -43,6 +53,8 @@ monoy InterruptMode 0.000000
monoy precision 0.010000
monoy ignorefault 0.000000
monoy AccessCode 2.000000
monoy failafter 3.000000
monoy maxretry 3.000000
monoy movecount 10.000000
# Motor curvem
curvem sign 1.000000
@ -54,6 +66,8 @@ curvem InterruptMode 0.000000
curvem precision 0.010000
curvem ignorefault 0.000000
curvem AccessCode 2.000000
curvem failafter 3.000000
curvem maxretry 3.000000
curvem movecount 10.000000
# Motor monophi
monophi sign 1.000000
@ -65,6 +79,8 @@ monophi InterruptMode 0.000000
monophi precision 0.010000
monophi ignorefault 0.000000
monophi AccessCode 2.000000
monophi failafter 3.000000
monophi maxretry 3.000000
monophi movecount 10.000000
# Motor monochi
monochi sign 1.000000
@ -76,17 +92,21 @@ monochi InterruptMode 0.000000
monochi precision 0.010000
monochi ignorefault 0.000000
monochi AccessCode 2.000000
monochi failafter 3.000000
monochi maxretry 3.000000
monochi movecount 10.000000
# Motor table
table sign 1.000000
table SoftZero 0.000000
table SoftLowerLim -180.000000
table SoftLowerLim -360.000000
table SoftUpperLim 360.000000
table Fixed -1.000000
table InterruptMode 0.000000
table precision 0.010000
table ignorefault 0.000000
table AccessCode 2.000000
table failafter 3.000000
table maxretry 3.000000
table movecount 10.000000
# Motor twothetad
twothetad sign 1.000000
@ -98,12 +118,14 @@ twothetad InterruptMode 0.000000
twothetad precision 0.010000
twothetad ignorefault 0.000000
twothetad AccessCode 2.000000
twothetad failafter 3.000000
twothetad maxretry 3.000000
twothetad movecount 10.000000
# Counter counter
counter SetPreset 30000000.000000
counter SetPreset 60000.000000
counter SetMode Monitor
banana CountMode monitor
banana preset 300.000000
banana preset 60000.000000
# Motor a1
a1 sign 1.000000
a1 SoftZero 0.000000
@ -114,28 +136,34 @@ a1 InterruptMode 0.000000
a1 precision 0.010000
a1 ignorefault 0.000000
a1 AccessCode 2.000000
a1 failafter 3.000000
a1 maxretry 3.000000
a1 movecount 10.000000
# Motor a2
a2 sign 1.000000
a2 SoftZero 0.000000
a2 SoftLowerLim 30.000000
a2 SoftLowerLim 35.000000
a2 SoftUpperLim 100.000000
a2 Fixed -1.000000
a2 InterruptMode 0.000000
a2 precision 0.010000
a2 ignorefault 0.000000
a2 AccessCode 2.000000
a2 failafter 3.000000
a2 maxretry 3.000000
a2 movecount 10.000000
# Motor a3
a3 sign 1.000000
a3 SoftZero 0.000000
a3 SoftLowerLim -180.000000
a3 SoftLowerLim -360.000000
a3 SoftUpperLim 360.000000
a3 Fixed -1.000000
a3 InterruptMode 0.000000
a3 precision 0.010000
a3 ignorefault 0.000000
a3 AccessCode 2.000000
a3 failafter 3.000000
a3 maxretry 3.000000
a3 movecount 10.000000
# Motor a4
a4 sign 1.000000
@ -147,6 +175,8 @@ a4 InterruptMode 0.000000
a4 precision 0.010000
a4 ignorefault 0.000000
a4 AccessCode 2.000000
a4 failafter 3.000000
a4 maxretry 3.000000
a4 movecount 10.000000
# Motor a5
a5 sign 1.000000
@ -158,6 +188,8 @@ a5 InterruptMode 0.000000
a5 precision 0.010000
a5 ignorefault 0.000000
a5 AccessCode 2.000000
a5 failafter 3.000000
a5 maxretry 3.000000
a5 movecount 10.000000
# Motor a6
a6 sign 1.000000
@ -169,6 +201,8 @@ a6 InterruptMode 0.000000
a6 precision 0.010000
a6 ignorefault 0.000000
a6 AccessCode 2.000000
a6 failafter 3.000000
a6 maxretry 3.000000
a6 movecount 10.000000
# Motor a7
a7 sign 1.000000
@ -180,6 +214,8 @@ a7 InterruptMode 0.000000
a7 precision 0.010000
a7 ignorefault 0.000000
a7 AccessCode 2.000000
a7 failafter 3.000000
a7 maxretry 3.000000
a7 movecount 10.000000
# Motor a8
a8 sign 1.000000
@ -191,6 +227,8 @@ a8 InterruptMode 0.000000
a8 precision 0.010000
a8 ignorefault 0.000000
a8 AccessCode 2.000000
a8 failafter 3.000000
a8 maxretry 3.000000
a8 movecount 10.000000
# Motor a9
a9 sign 1.000000
@ -202,10 +240,12 @@ a9 InterruptMode 0.000000
a9 precision 0.010000
a9 ignorefault 0.000000
a9 AccessCode 2.000000
a9 failafter 3.000000
a9 maxretry 3.000000
a9 movecount 10.000000
title D3C in Senfsosse
title Lieselotte Nass
title setAccess 2
user UNKNOWN
user Lukas
user setAccess 2
collimation UNKNOWN
collimation setAccess 2
@ -217,17 +257,25 @@ comment2 UNKNOWN
comment2 setAccess 2
comment3 UNKNOWN
comment3 setAccess 2
starttime 2007-02-20 11:27:09
starttime 2008-03-18 13:09:23
starttime setAccess 2
adress UNKNOWN
adress 2223 Luketown, 33 Luke Drive
adress setAccess 2
phone UNKNOWN
phone setAccess 2
fax UNKNOWN
fax setAccess 2
email UNKNOWN
email Luke@luke.ch
email setAccess 2
sample_mur 0.000000
sample_mur setAccess 2
lastdatafile /afs/psi.ch/user/k/koennecke/src/workspace/sics/mcstas/dmc/000/vdmc2007n000133.xml
lastdatafile /afs/psi.ch/user/k/koennecke/src/workspace/sics/mcstas/dmc/000/vdmc2008n000230.xml
lastdatafile setAccess 2
lastscancommand unknown scan
lastscancommand setAccess 2
# Counter lieselotte
lieselotte SetPreset 2.000000
lieselotte SetMode Timer
# Counter scancter
scancter SetPreset 2.000000
scancter SetMode Timer

View File

@ -8,6 +8,7 @@
-----------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include "sics.h"
#include "countdriv.h"
#include "mccontrol.h"
@ -76,6 +77,7 @@ static int McReadValues(struct __COUNTER *self){
if(status == HWFault){
self->iErrorCode = SCRIPTERROR;
}
self->fTime = time(NULL) - pMcStas->startTime;
return status;
}
/*--------------------------------------------------------------------------*/

View File

@ -987,10 +987,28 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon)
return 1;
}
/*---------------------------------------------------------------------------*/
static double getProtonAverage(pMesure self){
int np, i;
long *lData = NULL, lSum = 0;
np = GetScanNP(self->pScanner);
lData = (long *)malloc((np+1)*sizeof(long));
if(lData == NULL || np == 0){
return 0.;
}
memset(lData,0,(np+1)*sizeof(long));
GetScanMonitor(self->pScanner,2,lData, np);
for(i = 0; i < np; i++){
lSum += lData[i];
}
return (double)lSum/(double)np;
}
/*---------------------------------------------------------------------------*/
static int WriteReflection(pMesure self, float fHKL[3],SConnection *pCon)
{
float fSum, fSigma, fSet[4], fTemp, fPreset, fStep;
double prot;
static float fMax = 10.;
int iRet, i,ii, iLF, iNP;
char pBueffel[512], pNum[10], pTime[132];
@ -1107,8 +1125,9 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon)
SNXFormatTime(pBueffel,512);
GetScanVarStep(self->pScanner,0,&fStep);
fPreset = GetScanPreset(self->pScanner);
fprintf(self->fRefl,"%3d %7.4f %9.0f %7.3f %s\n",iNP,fStep,
fPreset,fTemp,pBueffel);
prot = getProtonAverage(self);
fprintf(self->fRefl,"%3d %7.4f %9.0f %7.3f %12f %s\n",iNP,fStep,
fPreset,fTemp,prot, pBueffel);
for(i = 0; i < iNP; i++)
{
for(ii = 0; ii < 10 && i < iNP; ii++)

View File

@ -171,8 +171,10 @@
fputs(pBueffel,fd);
sprintf(pBueffel,"%s AccessCode %f\n",name,ObVal(self->ParArray,USRIGHTS));
fputs(pBueffel,fd);
sprintf(pBueffel,"%s poscount %f\n",name,
ObVal(self->ParArray,POSCOUNT));
sprintf(pBueffel,"%s failafter %f\n",name,ObVal(self->ParArray,ECOUNT));
fputs(pBueffel,fd);
sprintf(pBueffel,"%s maxretry %f\n",name,ObVal(self->ParArray,POSCOUNT));
fputs(pBueffel,fd);
sprintf(pBueffel,"%s movecount %f\n",name,
ObVal(self->ParArray,MOVECOUNT));
fputs(pBueffel,fd);
@ -256,6 +258,8 @@ 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);
}
@ -351,6 +355,7 @@ static int evaluateStatus(pMotor self, SConnection *pCon)
}
if(newStatus == HWFault)
{
finishDriving(self,pCon);
MotorInterrupt(pCon,ObVal(self->ParArray,INT));
self->retryCount = 0;
}

View File

@ -298,13 +298,11 @@ static int MultiCounterSend(struct __COUNTER *self, char *pText,
return 0;
}
/*---------------------------------------------------------------------*/
static int MultiCounterError(struct __COUNTER *pData, int *iCode,
static int MultiCounterError(struct __COUNTER *pDriv, int *iCode,
char *error, int errlen){
pCounter pCount = NULL;
pCount = (pCounter)pData;
if(pCount->pDriv->iErrorCode == NOCOUNTERS){
if(pDriv->iErrorCode == NOCOUNTERS){
strncpy(error,"NO counters configured!",errlen);
} else {
strncpy(error,"Not Implemented", errlen);

1
mumo.c
View File

@ -872,6 +872,7 @@ static void RecoverNamPos(pMulMot self, int argc, char *argv[])
sprintf(pBueffel,"%s list of known named positions \n",
argv[0]);
Tcl_DStringAppend(&tString,pBueffel,strlen(pBueffel));
StringDictKillScan(self->pNamPos);
pPtr = StringDictGetNext(self->pNamPos,pError,131);
while(pPtr != NULL)
{

706
napi.c

File diff suppressed because it is too large Load Diff

39
napi.h
View File

@ -3,7 +3,7 @@
Application Program Interface Header File
Copyright (C) 2000-2005 Mark Koennecke, Uwe Filges
Copyright (C) 2000-2007 Mark Koennecke, Uwe Filges
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@ -19,9 +19,9 @@
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For further information, see <http://www.neutron.anl.gov/NeXus/>
For further information, see <http://www.nexusformat.org>
$Id: napi.h,v 1.10 2006/03/03 15:30:55 koennecke Exp $
$Id$
----------------------------------------------------------------------------*/
@ -29,14 +29,14 @@
#define NEXUSAPI
/* NeXus HDF45 */
#define NEXUS_VERSION "3.0.0" /* major.minor.patch */
#define NEXUS_VERSION "4.1.0" /* major.minor.patch */
#define CONSTCHAR const char
#ifdef _WIN32
//#define snprintf nxisnprintf
#ifdef _MSC_VER
#define snprintf nxisnprintf
extern int nxisnprintf(char* buffer, int len, const char* format, ... );
#endif /* _WIN32 */
#endif /* _MSC_VER */
typedef void* NXhandle; /* really a pointer to a NexusFile structure */
typedef int NXstatus;
@ -101,6 +101,8 @@ typedef struct {
#define NX_UINT16 23
#define NX_INT32 24
#define NX_UINT32 25
#define NX_INT64 26
#define NX_UINT64 27
#define NX_CHAR 4
#define NX_BINARY 21
@ -113,10 +115,8 @@ typedef struct {
typedef struct {
long iTag; /* HDF4 variable */
long iRef; /* HDF4 variable */
char iTag5[1024]; /* HDF5 variable */
char iRef5[1024]; /* HDF5 variable */
char iRefd[1024]; /* HDF5 variable */
char targetPath[1024]; /* XML path */
char targetPath[1024]; /* path to item to link */
int linkType; /* HDF5: 0 for group link, 1 for SDS link */
} NXlink;
#define NXMAXSTACK 50
@ -146,6 +146,7 @@ typedef struct {
# define NXputattr MANGLE(nxiputattr)
# define NXgetdataID MANGLE(nxigetdataid)
# define NXmakelink MANGLE(nximakelink)
# define NXmakenamedlink MANGLE(nximakenamedlink)
# define NXopensourcegroup MANGLE(nxiopensourcegroup)
# define NXmalloc MANGLE(nximalloc)
# define NXfree MANGLE(nxifree)
@ -166,6 +167,9 @@ typedef struct {
# define NXinitattrdir MANGLE(nxiinitattrdir)
# define NXsetnumberformat MANGLE(nxisetnumberformat)
# define NXsetcache MANGLE(nxisetcache)
# define NXinquirefile MANGLE(nxiinquirefile)
# define NXisexternalgroup MANGLE(nxiisexternalgroup)
# define NXlinkexternal MANGLE(nxilinkexternal)
/*
* FORTRAN helpers - for NeXus internal use only
@ -181,6 +185,11 @@ typedef struct {
/*
* Standard interface
*
* Functions added here are not automatically exported from
* a shared library/dll - the symbol name must also be added
* to the file src/nexus_symbols.txt
*
*/
#ifdef __cplusplus
@ -209,6 +218,7 @@ extern NXstatus NXputslab(NXhandle handle, void* data, int start[], int size[]
extern NXstatus NXgetdataID(NXhandle handle, NXlink* pLink);
extern NXstatus NXmakelink(NXhandle handle, NXlink* pLink);
extern NXstatus NXmakenamedlink(NXhandle handle, CONSTCHAR* newname, NXlink* pLink);
extern NXstatus NXopensourcegroup(NXhandle handle);
extern NXstatus NXgetdata(NXhandle handle, void* data);
@ -228,6 +238,10 @@ extern NXstatus NXinitattrdir(NXhandle handle);
extern NXstatus NXsetnumberformat(NXhandle handle,
int type, char *format);
extern NXstatus NXinquirefile(NXhandle handle, char *filename, int filenameBufferLength);
extern NXstatus NXisexternalgroup(NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass, char *url, int urlLen);
extern NXstatus NXlinkexternal(NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass, CONSTCHAR *url);
extern NXstatus NXmalloc(void** data, int rank, int dimensions[], int datatype);
extern NXstatus NXfree(void** data);
@ -238,6 +252,8 @@ extern NXstatus NXfree(void** data);
typedef void (*ErrFunc)(void *data, char *text);
extern void NXMSetError(void *pData, ErrFunc);
extern ErrFunc NXMGetError();
extern void NXMDisableErrorReporting();
extern void NXMEnableErrorReporting();
extern void (*NXIReportError)(void *pData,char *text);
extern void *NXpData;
extern char *NXIformatNeXusTime();
@ -266,6 +282,7 @@ extern NXstatus NXsetcache(long newVal);
NXstatus ( *nxputslab)(NXhandle handle, void* data, int start[], int size[]);
NXstatus ( *nxgetdataID)(NXhandle handle, NXlink* pLink);
NXstatus ( *nxmakelink)(NXhandle handle, NXlink* pLink);
NXstatus ( *nxmakenamedlink)(NXhandle handle, CONSTCHAR *newname, NXlink* pLink);
NXstatus ( *nxgetdata)(NXhandle handle, void* data);
NXstatus ( *nxgetinfo)(NXhandle handle, int* rank, int dimension[], int* datatype);
NXstatus ( *nxgetnextentry)(NXhandle handle, NXname name, NXname nxclass, int* datatype);

223
napi4.c
View File

@ -3,7 +3,7 @@
Application Program Interface (HDF4) Routines
Copyright (C) 1997-2002 Mark Koennecke, Przemek Klosowski
Copyright (C) 1997-2006 Mark Koennecke, Przemek Klosowski
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@ -21,7 +21,7 @@
For further information, see <http://www.neutron.anl.gov/NeXus/>
$Id: napi4.c,v 1.8 2006/03/31 15:24:53 koennecke Exp $
$Id$
----------------------------------------------------------------------------*/
#include <stdlib.h>
@ -64,13 +64,50 @@ extern void *NXpData;
assert(pRes->iNXID == NXSIGNATURE);
return pRes;
}
/*----------------------------------------------------------------------*/
static int findNapiClass(pNexusFile pFile, int groupRef, NXname nxclass)
{
NXname classText, linkClass;
int32 tags[2], attID, linkID, groupID;
groupID = Vattach(pFile->iVID,groupRef,"r");
Vgetclass(groupID, classText);
if(strcmp(classText,"NAPIlink") != 0)
{
/* normal group */
strcpy(nxclass,classText);
Vdetach(groupID);
return groupRef;
}
else
{
/* code for linked renamed groups */
attID = Vfindattr(groupID,"NAPIlink");
if(attID >= 0)
{
Vgetattr(groupID,attID, tags);
linkID = Vattach(pFile->iVID,tags[1],"r");
Vgetclass(linkID, linkClass);
Vdetach(groupID);
Vdetach(linkID);
strcpy(nxclass,linkClass);
return tags[1];
}
else
{
/* this allows for finding the NAPIlink group in NXmakenamedlink */
strcpy(nxclass,classText);
Vdetach(groupID);
return groupRef;
}
}
}
/* --------------------------------------------------------------------- */
static int32 NXIFindVgroup (pNexusFile pFile, CONSTCHAR *name, CONSTCHAR *nxclass)
{
int32 iNew, iRef, iTag;
int iN, i;
int iN, i, status;
int32 *pArray = NULL;
NXname pText;
@ -93,17 +130,16 @@ extern void *NXpData;
for (i = 0; i < iN; i++) {
iNew = Vattach (pFile->iVID, pArray[i], "r");
Vgetname (iNew, pText);
Vdetach(iNew);
if (strcmp (pText, name) == 0) {
Vgetclass (iNew, pText);
pArray[i] = findNapiClass(pFile,pArray[i],pText);
if (strcmp (pText, nxclass) == 0) {
/* found ! */
Vdetach (iNew);
iNew = pArray[i];
free (pArray);
return iNew;
}
}
Vdetach (iNew);
}
/* nothing found */
free (pArray);
@ -115,15 +151,13 @@ extern void *NXpData;
if (iTag == DFTAG_VG) {
iNew = Vattach (pFile->iVID, iRef, "r");
Vgetname (iNew, pText);
Vdetach(iNew);
if (strcmp (pText, name) == 0) {
Vgetclass (iNew, pText);
iRef = findNapiClass(pFile,iRef, pText);
if (strcmp (pText, nxclass) == 0) {
/* found ! */
Vdetach (iNew);
return iRef;
}
}
Vdetach (iNew);
}
} /* end for */
} /* end else */
@ -264,8 +298,15 @@ extern void *NXpData;
if (pFile->iCurrentSDS != 0) { /* SDS level */
iRet = SDgetinfo (pFile->iCurrentSDS, pNam, &iRank, iDim, &iType,
&iAtt);
} else { /* global level */
} else {
if(pFile->iCurrentVG == 0){
/* global level */
iRet = SDfileinfo (pFile->iSID, &iData, &iAtt);
} else {
/* group attribute */
iRet = Vnattrs(pFile->iCurrentVG);
iAtt = iRet;
}
}
if (iRet < 0) {
NXIReportError (NXpData, "ERROR: HDF cannot read attribute numbers");
@ -325,7 +366,7 @@ extern void *NXpData;
{
pNexusFile pNew = NULL;
char pBuffer[512];
char *time_puffer;
char *time_puffer = NULL;
char HDF_VERSION[64];
uint32 lmajor, lminor, lrelease;
int32 am1=0;
@ -350,8 +391,6 @@ extern void *NXpData;
}
memset (pNew, 0, sizeof (NexusFile));
time_puffer = NXIformatNeXusTime();
#if WRITE_OLD_IDENT /* not used at moment */
/*
* write something that can be used by OLE
@ -402,6 +441,8 @@ extern void *NXpData;
return NX_ERROR;
}
}
time_puffer = NXIformatNeXusTime();
if (am == NXACC_CREATE || am == NXACC_CREATE4) {
if (SDsetattr(pNew->iSID, "file_name", DFNT_CHAR8, strlen(filename), (char*)filename) < 0) {
NXIReportError (NXpData, "ERROR: HDF failed to store file_name attribute ");
@ -415,9 +456,11 @@ extern void *NXpData;
free(time_puffer);
return NX_ERROR;
}
free(time_puffer);
}
}
if (time_puffer != NULL) {
free(time_puffer);
}
/*
* Otherwise we try to create the file two times which makes HDF
@ -534,8 +577,6 @@ extern void *NXpData;
/*------------------------------------------------------------------------*/
NXstatus NX4opengroup (NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass)
{
pNexusFile pFile;
@ -566,7 +607,6 @@ extern void *NXpData;
NXIKillDir (pFile);
return NX_OK;
}
/* ------------------------------------------------------------------- */
@ -661,6 +701,11 @@ extern void *NXpData;
{
type=DFNT_FLOAT64;
}
else
{
NXIReportError (NXpData, "ERROR: invalid type in NX4makedata");
return NX_ERROR;
}
if (rank <= 0) {
sprintf (pBuffer, "ERROR: invalid rank specified for SDS %s",
@ -787,6 +832,11 @@ extern void *NXpData;
{
type=DFNT_FLOAT64;
}
else
{
NXIReportError (NXpData, "ERROR: invalid datatype in NX4compmakedata");
return NX_ERROR;
}
if (rank <= 0) {
sprintf (pBuffer, "ERROR: invalid rank specified for SDS %s",
@ -877,7 +927,7 @@ extern void *NXpData;
else
{
NXIReportError (NXpData, "Unknown compression method!");
NX_ERROR;
return NX_ERROR;
}
/* link into Vgroup, if in one */
if (pFile->iCurrentVG != 0) {
@ -900,7 +950,7 @@ extern void *NXpData;
pNexusFile pFile;
int32 iRank, iAtt, iType, iRet;
int32 iSize[MAX_VAR_DIMS];
int compress_typei;
int compress_typei = COMP_CODE_NONE;
NXname pBuffer;
char pError[512];
comp_info compstruct;
@ -962,7 +1012,7 @@ extern void *NXpData;
NXstatus NX4opendata (NXhandle fid, CONSTCHAR *name)
{
pNexusFile pFile;
int32 iNew;
int32 iNew, attID, tags[2];
char pBuffer[256];
int iRet;
@ -987,9 +1037,18 @@ extern void *NXpData;
/* clear pending attribute directories first */
NXIKillAttDir (pFile);
/* open the SDS */
/* open the SDS, thereby watching for linked SDS under a different name */
iNew = SDreftoindex (pFile->iSID, iNew);
pFile->iCurrentSDS = SDselect (pFile->iSID, iNew);
attID = SDfindattr(pFile->iCurrentSDS,"NAPIlink");
if(attID >= 0)
{
SDreadattr(pFile->iCurrentSDS,attID, tags);
SDendaccess(pFile->iCurrentSDS);
iNew = SDreftoindex (pFile->iSID, tags[1]);
pFile->iCurrentSDS = SDselect (pFile->iSID, iNew);
}
if (pFile->iCurrentSDS < 0) {
NXIReportError (NXpData, "ERROR: HDF error opening SDS");
pFile->iCurrentSDS = 0;
@ -1105,15 +1164,25 @@ extern void *NXpData;
{
type=DFNT_FLOAT64;
}
else
{
NXIReportError (NXpData, "ERROR: Invalid data type for HDF attribute");
return NX_ERROR;
}
if (pFile->iCurrentSDS != 0) {
/* SDS attribute */
iRet = SDsetattr (pFile->iCurrentSDS, (char*)name, (int32)type,
(int32)datalen, data);
} else {
if(pFile->iCurrentVG == 0){
/* global attribute */
iRet = SDsetattr (pFile->iSID, (char*)name, (int32)type,
(int32)datalen, data);
} else {
/* group attribute */
iRet = Vsetattr(pFile->iCurrentVG, (char *)name, (int32) type,
(int32)datalen,data);
}
}
iType = type;
if (iRet < 0) {
@ -1218,15 +1287,66 @@ extern void *NXpData;
return NX_ERROR;
}
Vaddtagref(pFile->iCurrentVG, sLink->iTag, sLink->iRef);
length = strlen(sLink->targetPath);
if(sLink->iTag == DFTAG_SDG || sLink->iTag == DFTAG_NDG ||
sLink->iTag == DFTAG_SDS)
{
dataID = SDreftoindex(pFile->iSID,sLink->iRef);
dataID = SDselect(pFile->iSID,dataID);
length = strlen(sLink->targetPath);
SDsetattr(dataID,name,type,length,sLink->targetPath);
SDendaccess(dataID);
}
else
{
dataID = Vattach(pFile->iVID,sLink->iRef,"w");
Vsetattr(dataID, (char *)name, type, (int32) length, sLink->targetPath);
Vdetach(dataID);
}
return NX_OK;
}
/* ------------------------------------------------------------------- */
NXstatus NX4makenamedlink (NXhandle fid, CONSTCHAR* newname, NXlink* sLink)
{
pNexusFile pFile;
int32 iVG, iRet, dataID, type = DFNT_CHAR8, length, dataType = NX_CHAR,
rank = 1, attType = NX_INT32;
int iDim[1];
char name[] = "target";
int tags[2];
pFile = NXIassert (fid);
if (pFile->iCurrentVG == 0) { /* root level, can not link here */
return NX_ERROR;
}
tags[0] = sLink->iTag;
tags[1] = sLink->iRef;
length = strlen(sLink->targetPath);
if(sLink->iTag == DFTAG_SDG || sLink->iTag == DFTAG_NDG ||
sLink->iTag == DFTAG_SDS)
{
iDim[0] = 1;
NX4makedata(fid,newname, dataType,rank,iDim);
NX4opendata(fid,newname);
NX4putattr(fid,"NAPIlink",tags, 2, attType);
NX4closedata(fid);
dataID = SDreftoindex(pFile->iSID,sLink->iRef);
dataID = SDselect(pFile->iSID,dataID);
SDsetattr(dataID,name,type,length,sLink->targetPath);
SDendaccess(dataID);
} else {
NX4makegroup(fid,newname,"NAPIlink");
NX4opengroup(fid,newname,"NAPIlink");
NX4putattr(fid,"NAPIlink",tags, 2, attType);
NX4closegroup(fid);
dataID = Vattach(pFile->iVID,sLink->iRef,"w");
Vsetattr(dataID, (char *)name, type, (int32) length, sLink->targetPath);
Vdetach(dataID);
}
return NX_OK;
}
@ -1236,8 +1356,7 @@ extern void *NXpData;
{
pNexusFile pFile;
pFile = NXIassert (fid);
printf("HDF4 link: iTag = %ld, iRef = %ld, target=\"%s\"\n",
sLink->iTag, sLink->iRef, sLink->targetPath);
printf("HDF4 link: iTag = %ld, iRef = %ld, target=\"%s\"\n", sLink->iTag, sLink->iRef, sLink->targetPath);
return NX_OK;
}
@ -1272,6 +1391,10 @@ extern void *NXpData;
ac = NXACC_READ;
}else if(pFile->iAccess[0] == 'w') {
ac = NXACC_RDWR;
} else {
NXIReportError (NXpData,
"ERROR: NX4flush failed to determine file access mode");
return NX_ERROR;
}
pCopy = (char *)malloc((strlen(pFileName)+10)*sizeof(char));
if(!pCopy) {
@ -1345,11 +1468,13 @@ extern void *NXpData;
return NX_EOD;
}
}
/* Next case: end of directory */
if (iCurDir >= pFile->iStack[pFile->iStackPtr].iNDir) {
NXIKillDir (pFile);
return NX_EOD;
}
/* Next case: we have data! supply it and increment counter */
if (pFile->iCurrentVG == 0) { /* root level */
iTemp = Vattach (pFile->iVID,
@ -1359,10 +1484,10 @@ extern void *NXpData;
return NX_ERROR;
}
Vgetname (iTemp, name);
Vgetclass (iTemp, nxclass);
Vdetach (iTemp);
findNapiClass(pFile, pFile->iStack[pFile->iStackPtr].iRefDir[iCurDir], nxclass);
*datatype = DFTAG_VG;
pFile->iStack[pFile->iStackPtr].iCurDir++;
Vdetach (iTemp);
return NX_OK;
} else { /* in Vgroup */
if (pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_VG) {/* Vgroup */
@ -1373,7 +1498,8 @@ extern void *NXpData;
return NX_ERROR;
}
Vgetname (iTemp, name);
Vgetclass (iTemp, nxclass);
Vdetach(iTemp);
findNapiClass(pFile, pFile->iStack[pFile->iStackPtr].iRefDir[iCurDir], nxclass);
*datatype = DFTAG_VG;
pFile->iStack[pFile->iStackPtr].iCurDir++;
Vdetach (iTemp);
@ -1511,7 +1637,7 @@ extern void *NXpData;
{
pNexusFile pFile;
int iRet;
int32 iPType, iCount;
int32 iPType, iCount, count;
pFile = NXIassert (fileid);
@ -1528,9 +1654,16 @@ extern void *NXpData;
return NX_EOD;
}
/* well, there must be data to copy */
if (pFile->iCurrentSDS == 0) { /* global attribute */
if (pFile->iCurrentSDS == 0) {
if(pFile->iCurrentVG == 0) {
/* global attribute */
iRet = SDattrinfo (pFile->iSID, pFile->iAtt.iCurDir,
pName, &iPType, &iCount);
}else {
/* group attribute */
iRet = Vattrinfo(pFile->iCurrentVG, pFile->iAtt.iCurDir,
pName, &iPType, &iCount, &count);
}
} else {
iRet = SDattrinfo (pFile->iCurrentSDS, pFile->iAtt.iCurDir,
pName, &iPType, &iCount);
@ -1552,7 +1685,7 @@ extern void *NXpData;
NXstatus NX4getattr (NXhandle fid, char *name, void *data, int* datalen, int* iType)
{
pNexusFile pFile;
int32 iNew, iType32;
int32 iNew, iType32, count;
void *pData = NULL;
int32 iLen, iRet;
int type;
@ -1604,8 +1737,13 @@ extern void *NXpData;
/* SDS attribute */
iNew = SDfindattr (pFile->iCurrentSDS, name);
} else {
if(pFile->iCurrentVG == 0){
/* global attribute */
iNew = SDfindattr (pFile->iSID, name);
} else {
/* group attribute */
iNew = Vfindattr(pFile->iCurrentVG, name);
}
}
if (iNew < 0) {
sprintf (pBuffer, "ERROR: attribute %s not found", name);
@ -1617,7 +1755,12 @@ extern void *NXpData;
if (pFile->iCurrentSDS != 0) {
iRet = SDattrinfo (pFile->iCurrentSDS, iNew, pNam, &iType32, &iLen);
} else {
if(pFile->iCurrentVG == 0){
iRet = SDattrinfo (pFile->iSID, iNew, pNam, &iType32, &iLen);
} else {
iRet = Vattrinfo(pFile->iCurrentVG,iNew,pNam,&iType32,&count,
&iLen);
}
}
if (iRet < 0) {
sprintf (pBuffer, "ERROR: HDF could not read attribute info");
@ -1637,7 +1780,11 @@ extern void *NXpData;
if (pFile->iCurrentSDS != 0) {
iRet = SDreadattr (pFile->iCurrentSDS, iNew, pData);
} else {
if(pFile->iCurrentVG == 0){
iRet = SDreadattr (pFile->iSID, iNew, pData);
} else {
iRet = Vgetattr(pFile->iCurrentVG, iNew, pData);
}
}
if (iRet < 0) {
sprintf (pBuffer, "ERROR: HDF could not read attribute data");
@ -1646,7 +1793,8 @@ extern void *NXpData;
}
/* copy data to caller */
memset (data, 0, *datalen);
if ((*datalen <= iLen) && (*iType == DFNT_UINT8 || *iType == DFNT_CHAR8 || *iType == DFNT_UCHAR8)) {
if ((*datalen <= iLen) &&
(*iType == DFNT_UINT8 || *iType == DFNT_CHAR8 || *iType == DFNT_UCHAR8)) {
iLen = *datalen - 1;
}
memcpy (data, pData, iLen);
@ -1670,8 +1818,14 @@ extern void *NXpData;
if (pFile->iCurrentSDS != 0) { /* SDS level */
iRet = SDgetinfo (pFile->iCurrentSDS, pNam, &iRank, iDim, &iType,
&iAtt);
} else { /* global level */
} else {
if(pFile->iCurrentVG == 0){
/* global level */
iRet = SDfileinfo (pFile->iSID, &iData, &iAtt);
} else {
iRet = Vnattrs(pFile->iCurrentVG);
iAtt = iRet;
}
}
if (iRet < 0) {
NXIReportError (NXpData, "NX_ERROR: HDF cannot read attribute numbers");
@ -1793,6 +1947,7 @@ void NX4assignFunctions(pNexusFunction fHandle)
fHandle->nxputslab=NX4putslab;
fHandle->nxgetdataID=NX4getdataID;
fHandle->nxmakelink=NX4makelink;
fHandle->nxmakenamedlink=NX4makenamedlink;
fHandle->nxgetdata=NX4getdata;
fHandle->nxgetinfo=NX4getinfo;
fHandle->nxgetnextentry=NX4getnextentry;

1308
napi5.c

File diff suppressed because it is too large Load Diff

22
napiconfig.h Executable file
View File

@ -0,0 +1,22 @@
#ifndef NAPICONFIG_H
#define NAPICONFIG_H
#include <nxconfig.h>
/*
* Type definitions
*/
#ifdef HAVE_STDINT_H
#include <stdint.h>
#else
typedef signed char int8_t;
typedef short int int16_t;
typedef int int32_t;
typedef long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long uint64_t;
#endif /* HAVE_STDINT_H */
#endif /* NAPICONFIG_H */

34
napiu.c
View File

@ -21,10 +21,10 @@
For further information, see <http://www.nexus.anl.gov/>
$Id: napiu.c,v 1.1 2005/10/05 07:20:18 koennecke Exp $
$Id$
----------------------------------------------------------------------------*/
static const char* rscid = "$Id: napiu.c,v 1.1 2005/10/05 07:20:18 koennecke Exp $"; /* Revision interted by CVS */
static const char* rscid = "$Id$"; /* Revision interted by CVS */
#include <stdlib.h>
#include <assert.h>
@ -41,7 +41,7 @@ static const char* rscid = "$Id: napiu.c,v 1.1 2005/10/05 07:20:18 koennecke Exp
} \
}
NXstatus CALLING_STYLE NXUwriteglobals(NXhandle file_id, const char* user, const char* affiliation, const char* address, const char* telephone_number, const char* fax_number, const char* email)
NXstatus NXUwriteglobals(NXhandle file_id, const char* user, const char* affiliation, const char* address, const char* telephone_number, const char* fax_number, const char* email)
{
DO_GLOBAL(user);
DO_GLOBAL(affiliation);
@ -53,7 +53,7 @@ static const char* rscid = "$Id: napiu.c,v 1.1 2005/10/05 07:20:18 koennecke Exp
}
/* NXUwritegroup creates and leaves open a group */
NXstatus CALLING_STYLE NXUwritegroup(NXhandle file_id, const char* group_name, const char* group_class)
NXstatus NXUwritegroup(NXhandle file_id, const char* group_name, const char* group_class)
{
int status;
status = NXmakegroup(file_id, group_name, group_class);
@ -64,22 +64,22 @@ static const char* rscid = "$Id: napiu.c,v 1.1 2005/10/05 07:20:18 koennecke Exp
return status;
}
NXstatus CALLING_STYLE NXUwritedata(NXhandle file_id, const char* data_name, const void* data, int data_type, int rank, const int dim[], const char* units, const int start[], const int size[])
NXstatus NXUwritedata(NXhandle file_id, const char* data_name, const void* data, int data_type, int rank, const int dim[], const char* units, const int start[], const int size[])
{
return NX_OK;
}
NXstatus CALLING_STYLE NXUreaddata(NXhandle file_id, const char* data_name, void* data, char* units, const int start[], const int size[])
NXstatus NXUreaddata(NXhandle file_id, const char* data_name, void* data, char* units, const int start[], const int size[])
{
return NX_OK;
}
NXstatus CALLING_STYLE NXUwritehistogram(NXhandle file_id, const char* data_name, const void* data, const char* units)
NXstatus NXUwritehistogram(NXhandle file_id, const char* data_name, const void* data, const char* units)
{
return NX_OK;
}
NXstatus CALLING_STYLE NXUreadhistogram(NXhandle file_id, const char* data_name, void* data, char* units)
NXstatus NXUreadhistogram(NXhandle file_id, const char* data_name, void* data, char* units)
{
return NX_OK;
}
@ -88,7 +88,7 @@ static int NXcompress_type = 0;
static int NXcompress_size = 0;
/* NXUsetcompress sets the default compression type and minimum size */
NXstatus CALLING_STYLE NXUsetcompress(NXhandle file_id, int comp_type, int comp_size)
NXstatus NXUsetcompress(NXhandle file_id, int comp_type, int comp_size)
{
int status;
if (comp_type == NX_COMP_LZW || comp_type == NX_COMP_HUF ||
@ -110,7 +110,7 @@ static int NXcompress_size = 0;
}
/* !NXUfindgroup finds if a NeXus group of the specified name exists */
NXstatus CALLING_STYLE NXUfindgroup(NXhandle file_id, const char* group_name, char* group_class)
NXstatus NXUfindgroup(NXhandle file_id, const char* group_name, char* group_class)
{
int status, n;
NXname vname, vclass;
@ -122,38 +122,38 @@ static int NXcompress_size = 0;
return NX_OK;
}
NXstatus CALLING_STYLE NXUfindclass(NXhandle file_id, const char* group_class, char* group_name, int find_index)
NXstatus NXUfindclass(NXhandle file_id, const char* group_class, char* group_name, int find_index)
{
return NX_OK;
}
/* NXUfinddata finds if a NeXus data item is in the current group */
NXstatus CALLING_STYLE NXUfinddata(NXhandle file_id, const char* data_name)
NXstatus NXUfinddata(NXhandle file_id, const char* data_name)
{
return NX_OK;
}
NXstatus CALLING_STYLE NXUfindattr(NXhandle file_id, const char* attr_name)
NXstatus NXUfindattr(NXhandle file_id, const char* attr_name)
{
return NX_OK;
}
NXstatus CALLING_STYLE NXUfindsignal(NXhandle file_id, int signal, char* data_name, int* data_rank, int* data_type, int data_dimensions[])
NXstatus NXUfindsignal(NXhandle file_id, int signal, char* data_name, int* data_rank, int* data_type, int data_dimensions[])
{
return NX_OK;
}
NXstatus CALLING_STYLE NXUfindaxis(NXhandle file_id, int axis, int primary, char* data_name, int* data_rank, int* data_type, int data_dimensions[])
NXstatus NXUfindaxis(NXhandle file_id, int axis, int primary, char* data_name, int* data_rank, int* data_type, int data_dimensions[])
{
return NX_OK;
}
NXstatus CALLING_STYLE NXUfindlink(NXhandle file_id, NXlink* group_id, const char* group_class)
NXstatus NXUfindlink(NXhandle file_id, NXlink* group_id, const char* group_class)
{
return NX_OK;
}
NXstatus CALLING_STYLE NXUresumelink(NXhandle file_id, NXlink group_id)
NXstatus NXUresumelink(NXhandle file_id, NXlink group_id)
{
return NX_OK;
}

Some files were not shown because too many files have changed in this diff Show More