PSI UPDATE
r2720 | ffr | 2008-10-13 15:40:07 +1100 (Mon, 13 Oct 2008) | 2 lines
This commit is contained in:
@ -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
|
||||
|
16
HistMem.h
16
HistMem.h
@ -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
|
||||
|
@ -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
70
README
Normal 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
|
||||
|
||||
|
42
SCinter.c
42
SCinter.c
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
19
SCinter.h
19
SCinter.h
@ -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
|
||||
------------------------------------------------------------------------*/
|
||||
|
22
SICSmain.c
22
SICSmain.c
@ -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
19
alias.c
@ -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;
|
||||
}
|
||||
|
2
alias.h
2
alias.h
@ -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
537
ascon.c
Normal 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
82
ascon.h
Normal 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
156
ascon.i
Normal 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
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
15
asyncqueue.c
15
asyncqueue.c
@ -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);
|
||||
|
@ -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.
|
||||
*
|
||||
|
244
commandlog.c
244
commandlog.c
@ -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 */
|
||||
{
|
||||
|
@ -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[]);
|
||||
|
||||
|
@ -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
316
conman.c
@ -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)
|
||||
|
27
conman.h
27
conman.h
@ -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
5
danu.c
@ -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
|
||||
|
22
devexec.c
22
devexec.c
@ -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
361
devser.c
Normal 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
123
devser.h
Normal 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
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
68
errormsg.c
Normal 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
32
errormsg.h
Normal 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
|
@ -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);
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
@ -41,7 +41,7 @@
|
||||
int iWarned;
|
||||
int iTcl;
|
||||
int iStop;
|
||||
SCStore conn;
|
||||
SCStore *conn;
|
||||
char *creationArgs;
|
||||
char *runScript;
|
||||
void *pPrivate;
|
||||
|
@ -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]
|
||||
|
@ -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
15
event.h
@ -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
|
||||
|
12
event.tex
12
event.tex
@ -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]
|
||||
|
4
event.w
4
event.w
@ -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
16
exe.w
@ -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 @{
|
||||
|
55
exebuf.c
55
exebuf.c
@ -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;
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
17
exebuf.h
17
exebuf.h
@ -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
|
||||
|
4
exebuf.i
4
exebuf.i
@ -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
223
exeman.c
@ -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){
|
||||
|
3
exeman.h
3
exeman.h
@ -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
|
||||
|
6
exeman.i
6
exeman.i
@ -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
305
fomerge.c
@ -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
622
genericcontroller.c
Normal 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
37
genericcontroller.h
Normal 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
19
geninter.c
Normal 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
19
geninter.h
Normal 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
497
hdbqueue.c
Normal 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
15
hdbqueue.h
Normal 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_*/
|
684
hipadaba.c
684
hipadaba.c
@ -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 = ¤t->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);
|
||||
|
238
hipadaba.h
238
hipadaba.h
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
22
histsim.c
22
histsim.c
@ -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
6
hkl.c
@ -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
153
hmdata.c
@ -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;
|
||||
}
|
||||
|
2
hmdata.h
2
hmdata.h
@ -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
293
hmslave.c
Normal 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;
|
||||
}
|
3
ifile.c
3
ifile.c
@ -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)
|
||||
|
150
initializer.c
150
initializer.c
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
15
lld_blob.c
15
lld_blob.c
@ -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 )
|
||||
|
@ -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
369
logger.c
Normal 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
29
logger.h
Normal 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
524
logreader.c
Normal 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
113
logsetup.c
Normal 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
13
macosx_def
Normal 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
10
macro.c
@ -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);
|
||||
|
13
make_gen
13
make_gen
@ -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
42
makefile_macosx
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
#ifdef __TURBOC__
|
||||
#include <alloc.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include "matrix.h"
|
||||
|
@ -19,7 +19,7 @@
|
||||
#ifdef __TURBOC__
|
||||
#include <alloc.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include "matrix.h"
|
||||
|
@ -20,7 +20,7 @@
|
||||
#ifdef __TURBOC__
|
||||
#include <alloc.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include "matrix.h"
|
||||
|
@ -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
116
mclist.c
Normal 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
177
mclist.h
Normal 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
|
@ -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",
|
||||
|
@ -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
174
mcstas/dmc/gumibatch.tcl
Normal 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
80
mcstas/dmc/gumxml.tcl
Normal 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
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 ,]
|
||||
}
|
||||
#-----------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
23
mesure.c
23
mesure.c
@ -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++)
|
||||
|
9
motor.c
9
motor.c
@ -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;
|
||||
}
|
||||
|
@ -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
1
mumo.c
@ -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)
|
||||
{
|
||||
|
39
napi.h
39
napi.h
@ -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
223
napi4.c
@ -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;
|
||||
|
22
napiconfig.h
Executable file
22
napiconfig.h
Executable 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
34
napiu.c
@ -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
Reference in New Issue
Block a user