diff --git a/conman.c b/conman.c
index 222a07e3..5b379708 100644
--- a/conman.c
+++ b/conman.c
@@ -652,7 +652,7 @@ static void writeToLogFiles(SConnection *self, char *buffer)
SICSLogWrite(buffer,iOut);
/* write to commandlog if user or manager privilege */
- if(SCGetRights(self) <= usUser)
+ if(SCGetRights(self) <= usUser && self->iMacro != 1)
{
sprintf(pBueffel,"To sock %d :",iRet);
WriteToCommandLog(pBueffel,buffer);
diff --git a/devexec.c b/devexec.c
index 9c5718e9..bf333406 100644
--- a/devexec.c
+++ b/devexec.c
@@ -419,7 +419,10 @@
case HWFault: /* real HW error: burning, no net etc.. */
ExeInterest(self, pDev, "finished with problem");
DeleteDevEntry(pDev);
+ pDev = NULL;
+ LLDnodeDataTo(self->iList,&pDev);
LLDnodeDelete(self->iList);
+ iRet = LLDnodePtr2Prev(self->iList);
self->iStatus = DEVERROR;
if(pDrivInt)
{
diff --git a/exebuf.c b/exebuf.c
index b693d36a..b38dfd7a 100644
--- a/exebuf.c
+++ b/exebuf.c
@@ -129,7 +129,7 @@ static pDynString findBlockEnd(pExeBuf self){
return NULL;
}
buffer = GetCharArray(self->bufferContent);
- if(self->end != 0){
+ if(self->end != -1){
self->start = self->end + 1;
}
for(i = self->start; i < strlen(buffer); i++){
@@ -162,7 +162,7 @@ int exeBufProcess(pExeBuf self, SicsInterp *pSics,
assert(pSics);
self->start = 0;
- self->end = 0;
+ self->end = -1;
self->lineno = 0;
pTcl = InterpGetTcl(pSics);
diff --git a/histmem.c b/histmem.c
index 250c5b47..db0d79ef 100644
--- a/histmem.c
+++ b/histmem.c
@@ -629,7 +629,7 @@
if(isInTOFMode(self->pDriv->data))
{
iDim[*nDim] = getNoOfTimebins(self->pDriv->data);
- *nDim ++;
+ *nDim = *nDim + 1;
}
return 1;
}
diff --git a/hkl.c b/hkl.c
index c7ac0dee..34df8d0f 100644
--- a/hkl.c
+++ b/hkl.c
@@ -887,6 +887,30 @@ static int calculateNormalBeamOmega(MATRIX z1, pHKL self,
return 0;
}
+/*------------------------------------------------------------------------*/
+static void stopHKLMotors(pHKL self)
+{
+ if(self->pTheta != NULL)
+ {
+ self->pTheta->pDrivInt->Halt(self->pTheta);
+ }
+ if(self->pOmega != NULL)
+ {
+ self->pOmega->pDrivInt->Halt(self->pOmega);
+ }
+ if(self->pChi != NULL)
+ {
+ self->pChi->pDrivInt->Halt(self->pChi);
+ }
+ if(self->pPhi != NULL)
+ {
+ self->pPhi->pDrivInt->Halt(self->pPhi);
+ }
+ if(self->pNu != NULL)
+ {
+ self->pNu->pDrivInt->Halt(self->pNu);
+ }
+}
/*-------------------------------------------------------------------------*/
int RunHKL(pHKL self, float fHKL[3],
float fPsi, int iHamil, SConnection *pCon)
@@ -911,7 +935,7 @@ static int calculateNormalBeamOmega(MATRIX z1, pHKL self,
if(!iRet)
{
SCWrite(pCon,"ERROR: cannot start two theta motor",eError);
- StopExe(pServ->pExecutor,"all");
+ stopHKLMotors(self);
return 0;
}
@@ -921,7 +945,7 @@ static int calculateNormalBeamOmega(MATRIX z1, pHKL self,
if(!iRet)
{
SCWrite(pCon,"ERROR: cannot start omega motor",eError);
- StopExe(pServ->pExecutor,"all");
+ stopHKLMotors(self);
return 0;
}
@@ -933,7 +957,6 @@ static int calculateNormalBeamOmega(MATRIX z1, pHKL self,
pDum->pDescriptor, pDum, pCon,fSet[2]);
if(!iRet)
{
- StopExe(pServ->pExecutor,"all");
SCWrite(pCon,"ERROR: cannot start nu motor",eError);
return 0;
}
@@ -953,7 +976,7 @@ static int calculateNormalBeamOmega(MATRIX z1, pHKL self,
if(!iRet)
{
SCWrite(pCon,"ERROR: cannot start chi motor",eError);
- StopExe(pServ->pExecutor,"all");
+ stopHKLMotors(self);
return 0;
}
pDum = (pDummy)self->pPhi;
@@ -962,7 +985,7 @@ static int calculateNormalBeamOmega(MATRIX z1, pHKL self,
if(!iRet)
{
SCWrite(pCon,"ERROR: cannot start phi",eError);
- StopExe(pServ->pExecutor,"all");
+ stopHKLMotors(self);
return 0;
}
for(i = 0; i < 3; i++)
diff --git a/hklmot.c b/hklmot.c
index aeece55f..6f7c66cb 100644
--- a/hklmot.c
+++ b/hklmot.c
@@ -107,10 +107,10 @@ static int HKLCheckStatus(void *pData, SConnection *pCon){
assert(self != NULL);
if(self->pHkl->targetDirty == 1){
status = RunHKL(self->pHkl,self->pHkl->targetHKL,.0,0,pCon);
+ self->pHkl->targetDirty = 0;
if(status != 1){
return HWFault;
}
- self->pHkl->targetDirty = 0;
return HWBusy;
} else {
return checkMotors(self,pCon);
diff --git a/mesure.c b/mesure.c
index ce68d1c8..dc182539 100644
--- a/mesure.c
+++ b/mesure.c
@@ -633,6 +633,8 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon)
ClearScanVar(self->pScanner);
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pCOmega,
fStart, stepWidth);
+ snprintf(pBueffel,131,"Scanning om from %f with step %f", fStart, stepWidth);
+ SCWrite(pCon,pBueffel,eValue);
/*
Oksana does not want o2t scans to be tightly coupled, this is why we
cannot use the normal o2t scan variable. Instead we calculate new limits and
@@ -648,6 +650,8 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon)
fStart -= (np/2.)*stepWidth;
AddScanVar(self->pScanner, pServ->pSics,pCon,self->pC2Theta,
fStart, stepWidth);
+ snprintf(pBueffel,131,"Scanning 2theta from %f with step %f", fStart, stepWidth);
+ SCWrite(pCon,pBueffel,eValue);
}
/*
@@ -665,10 +669,7 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon)
}
/* do the scan */
- snprintf(pBueffel,131,"Scanning %s, step %f, np = %d",scanVar, stepWidth, np);
- SCWrite(pCon,pBueffel,eWarning);
free(scanVar);
-
if(self->iCompact)
{
self->pScanner->CollectScanData = CompactScanData;
diff --git a/network.c b/network.c
index b6bfb62b..d2ec21bb 100644
--- a/network.c
+++ b/network.c
@@ -154,8 +154,8 @@ CreateSocketAdress(
i = sizeof(struct linger);
lili.l_onoff = 1;
lili.l_linger = 1;
-/* setsockopt(pRes->sockid,SOL_SOCKET,SO_LINGER,&lili,i);
-*/
+ setsockopt(pRes->sockid,SOL_SOCKET,SO_LINGER,&lili,i);
+
pRes->iType = PORT;
pRes->lMagic = NETMAGIC;
return pRes;
diff --git a/nxxml.c b/nxxml.c
new file mode 100644
index 00000000..3b0c01ec
--- /dev/null
+++ b/nxxml.c
@@ -0,0 +1,1443 @@
+/*
+ * This is the implementation file for the XML file driver
+ * for NeXus
+ *
+ * Copyright (C) 2004 Mark Koennecke
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * 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
+ */
+#include
+#include
+#include
+#include
+#include
+#include "nxio.h"
+#include "nxdataset.h"
+
+
+extern void *NXpData;
+extern char *NXIformatNeXusTime();
+
+
+/*----------------------- our data structures --------------------------
+ One might wonder why a node stack is still needed even if this API
+ operates on top of a tree API. The reason for this are the links.
+ Following a link on any NXopenpath, data means a jump through the
+ whole tree. In order to correctly return from such adventures,
+ a stack is needed. Moreover we need it in order to keep track of the
+ state of search operations.
+
+ The true NXroot node is always at stack[0]. The root in the data
+ structure is the ?xml element. The latter one is needed to store
+ the tree.
+-----------------------------------------------------------------------*/
+typedef struct {
+ mxml_node_t *current;
+ mxml_node_t *currentChild;
+ int currentAttribute;
+}xmlStack;
+/*---------------------------------------------------------------------*/
+typedef struct {
+ mxml_node_t *root; /* root node */
+ int readOnly; /* read only flag */
+ int stackPointer; /* stack pointer */
+ char filename[1024]; /* file name, for NXflush, NXclose */
+ xmlStack stack[NXMAXSTACK]; /* stack */
+}XMLNexus, *pXMLNexus;
+/*===================== support functions ===============================*/
+static int isDataNode(mxml_node_t *node){
+ if(mxmlElementGetAttr(node,"name") != NULL){
+ return 0;
+ }
+ if(strcmp(node->value.element.name,"NXroot") == 0){
+ return 0;
+ }
+ if(strcmp(node->value.element.name,"NAPIlink") == 0){
+ return 0;
+ }
+ return 1;
+}
+/*----------------------------------------------------------------------*/
+extern char *stptok(char *s, char *tok, size_t toklen, char *brk);
+
+static mxml_node_t *getLinkTarget(pXMLNexus xmlHandle, const char *target){
+ mxml_node_t *node = NULL;
+ mxml_node_t *testNode = NULL;
+ char path[132], *pPtr;
+
+ pPtr = (char *)target + 1;
+ node = xmlHandle->stack[0].current;
+ while((pPtr = stptok(pPtr,path,131,"/")) != NULL){
+ /*
+ search for group node
+ */
+ testNode = mxmlFindElement(node,node,NULL,"name",path,MXML_DESCEND_FIRST);
+ if(testNode == NULL){
+ /*
+ it can still be a data node
+ */
+ testNode = mxmlFindElement(node,node,path,NULL,NULL,MXML_DESCEND_FIRST);
+ }
+ if(testNode == NULL){
+ NXIReportError(NXpData,"Cannot follow broken link");
+ return NULL;
+ } else {
+ node = testNode;
+ }
+ }
+ return node;
+}
+/*==================== file functions ===================================*/
+static void errorCallbackForMxml(const char *txt){
+ NXIReportError(NXpData,(char *)txt);
+}
+/*-----------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXopen(CONSTCHAR *filename, NXaccess am,
+ NXhandle* pHandle) {
+ pXMLNexus xmlHandle = NULL;
+ FILE *fp = NULL;
+ char *time_buffer = NULL;
+ mxml_node_t *current;
+
+ /*
+ allocate data
+ */
+ xmlHandle = (pXMLNexus)malloc(sizeof(XMLNexus));
+ if(!xmlHandle){
+ NXIReportError(NXpData, "Out of memory allocating XML file handle");
+ return NX_ERROR;
+ }
+ memset(xmlHandle,0,sizeof(XMLNexus));
+
+ /*
+ initialize mxml XML parser
+ */
+ mxmlSetCustomHandlers(nexusLoadCallback, nexusWriteCallback);
+ initializeNumberFormats();
+ mxmlSetErrorCallback(errorCallbackForMxml);
+
+ /*
+ open file
+ */
+ strncpy(xmlHandle->filename,filename,1023);
+ switch(am){
+ case NXACC_READ:
+ xmlHandle->readOnly = 1;
+ case NXACC_RDWR:
+ fp = fopen(filename,"r");
+ if(fp == NULL){
+ NXIReportError(NXpData,"Failed to open file:");
+ NXIReportError(NXpData,(char *)filename);
+ free(xmlHandle);
+ return NX_ERROR;
+ }
+ xmlHandle->root = mxmlLoadFile(NULL,fp,nexusTypeCallback);
+ xmlHandle->stack[0].current = mxmlFindElement(xmlHandle->root,
+ xmlHandle->root,
+ "NXroot",
+ NULL,NULL,
+ MXML_DESCEND);
+ xmlHandle->stack[0].currentChild = NULL;
+ xmlHandle->stack[0].currentAttribute = 0;
+ fclose(fp);
+ break;
+ case NXACC_CREATEXML:
+ xmlHandle->root = mxmlNewElement(NULL,
+ "?xml version=\"1.0\" encoding=\"UTF-8\"?");
+ current = mxmlNewElement(xmlHandle->root,"NXroot");
+ mxmlElementSetAttr(current,"NeXus_version",NEXUS_VERSION);
+ mxmlElementSetAttr(current,"XML_version","mxml-2.0");
+ mxmlElementSetAttr(current,"file_name",filename);
+ time_buffer = NXIformatNeXusTime();
+ if(time_buffer != NULL){
+ mxmlElementSetAttr(current,"file_time",time_buffer);
+ free(time_buffer);
+ }
+ xmlHandle->stack[0].current = current;
+ xmlHandle->stack[0].currentChild = NULL;
+ xmlHandle->stack[0].currentAttribute = 0;
+ break;
+ default:
+ NXIReportError(NXpData,"Bad access parameter specified in NXXopen");
+ return NX_ERROR;
+ }
+ if(xmlHandle->stack[0].current == NULL){
+ NXIReportError(NXpData,
+ "No NXroot element in XML-file, no NeXus-XML file");
+ return NX_ERROR;
+ }
+
+ *pHandle = xmlHandle;
+ return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXclose (NXhandle* fid){
+ pXMLNexus xmlHandle = NULL;
+ FILE *fp = NULL;
+
+ xmlHandle = (pXMLNexus)*fid;
+ assert(xmlHandle);
+
+ if(xmlHandle->readOnly == 0) {
+ fp = fopen(xmlHandle->filename,"w");
+ if(fp == NULL){
+ NXIReportError(NXpData,"Failed to open NeXus XML file for writing");
+ return NX_ERROR;
+ }
+ mxmlSaveFile(xmlHandle->root,fp,NXwhitespaceCallback);
+ fclose(fp);
+ }
+ mxmlDelete(xmlHandle->root);
+ free(xmlHandle);
+ *fid = NULL;
+ return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXflush(NXhandle *fid){
+ pXMLNexus xmlHandle = NULL;
+ FILE *fp = NULL;
+
+ xmlHandle = (pXMLNexus)*fid;
+ assert(xmlHandle);
+
+ if(xmlHandle->readOnly == 0) {
+ fp = fopen(xmlHandle->filename,"w");
+ if(fp == NULL){
+ NXIReportError(NXpData,"Failed to open NeXus XML file for writing");
+ return NX_ERROR;
+ }
+ mxmlSaveFile(xmlHandle->root,fp,NXwhitespaceCallback);
+ fclose(fp);
+ }
+ return NX_OK;
+}
+/*=======================================================================
+ Group functions
+=========================================================================*/
+NXstatus CALLING_STYLE NXXmakegroup (NXhandle fid, CONSTCHAR *name,
+ CONSTCHAR *nxclass){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *newGroup = NULL;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ NXIReportError(NXpData,"Close dataset before trying to create a group");
+ return NX_ERROR;
+ }
+
+ newGroup = mxmlNewElement(xmlHandle->stack[xmlHandle->stackPointer].current,
+ nxclass);
+ if(!newGroup){
+ NXIReportError(NXpData,"failed to allocate new group");
+ return NX_ERROR;
+ }
+ mxmlElementSetAttr(newGroup,"name",name);
+ return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+static mxml_node_t *searchGroupLinks(pXMLNexus xmlHandle, CONSTCHAR *name,
+ CONSTCHAR *nxclass){
+ mxml_node_t *linkNode = NULL;
+ mxml_node_t *current;
+ mxml_node_t *test = NULL;
+ const char *linkTarget;
+
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+ linkNode = current;
+ while((linkNode = mxmlFindElement(linkNode,current,"NAPIlink",NULL,NULL,
+ MXML_DESCEND_FIRST)) != NULL){
+ linkTarget = mxmlElementGetAttr(linkNode,"target");
+ test = getLinkTarget(xmlHandle,linkTarget);
+ if(test != NULL){
+ if(strcmp(test->value.element.name,nxclass) == 0){
+ if(strcmp(mxmlElementGetAttr(test,"name"),name) == 0){
+ return test;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+/*------------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXopengroup (NXhandle fid, CONSTCHAR *name,
+ CONSTCHAR *nxclass){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *newGroup = NULL;
+ char error[1024];
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ NXIReportError(NXpData,"Close dataset before trying to open a group");
+ return NX_ERROR;
+ }
+ newGroup = mxmlFindElement(xmlHandle->stack[xmlHandle->stackPointer].current,
+ xmlHandle->stack[xmlHandle->stackPointer].current,
+ nxclass,
+ "name",
+ name,
+ MXML_DESCEND_FIRST);
+ if(newGroup == NULL){
+ newGroup = searchGroupLinks(xmlHandle,name,nxclass);
+ }
+ if(!newGroup){
+ snprintf(error,1023,"Failed to open %s, %s",name,nxclass);
+ NXIReportError(NXpData,error);
+ return NX_ERROR;
+ }
+ xmlHandle->stackPointer++;
+ xmlHandle->stack[xmlHandle->stackPointer].current = newGroup;
+ xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL;
+ xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 0;
+ return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXclosegroup (NXhandle fid){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *newGroup = NULL;
+ char error[1024];
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ /*
+ silently fix this
+ */
+ NXXclosedata(fid);
+ }
+ if(xmlHandle->stackPointer > 0){
+ xmlHandle->stackPointer--;
+ }
+ return NX_OK;
+}
+/*=========================================================================
+ dataset functions
+=========================================================================*/
+NXstatus CALLING_STYLE NXXcompmakedata (NXhandle fid, CONSTCHAR *name,
+ int datatype,
+ int rank,
+ int dimensions[],
+ int compress_type, int chunk_size[]){
+ /*
+ compression does not relly make sense with XML
+ */
+ return NXXmakedata(fid,name,datatype,rank,dimensions);
+}
+/*-----------------------------------------------------------------------*/
+static char *buildTypeString(int datatype, int rank, int dimensions[]){
+ char *typestring = NULL;
+ char pNumber[20];
+ int i;
+
+ /*
+ allocate data
+ */
+ typestring = (char *)malloc(132*sizeof(char));
+ if(!typestring){
+ NXIReportError(NXpData,"Failed to allocate typestring");
+ return NULL;
+ }
+ memset(typestring,0,132*sizeof(char));
+
+ getNumberText(datatype,typestring,130);
+ if(rank > 1 || dimensions[0] > 1) {
+ strcat(typestring,"[");
+ snprintf(pNumber,19,"%d",dimensions[0]);
+ strncat(typestring,pNumber,130-strlen(typestring));
+ for(i = 1; i < rank; i++){
+ snprintf(pNumber,19,",%d",dimensions[i]);
+ strncat(typestring,pNumber,130-strlen(typestring));
+ }
+ strcat(typestring,"]");
+ }
+ return typestring;
+}
+/*------------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXmakedata (NXhandle fid,
+ CONSTCHAR *name, int datatype,
+ int rank, int dimensions[]){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *dataNode = NULL;
+ mxml_node_t *newData = NULL;
+ mxml_node_t *current;
+ char *typestring;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ NXIReportError(NXpData,"Close dataset before trying to create a dataset");
+ return NX_ERROR;
+ }
+ if(dimensions[0] < 0){
+ NXIReportError(NXpData,
+ "NeXus XML-API does not support unlimited dimensions");
+ return NX_ERROR;
+ }
+
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+ /*
+ NX_CHAR maps to MXML_OPAQUE datasets
+ */
+ dataNode = mxmlNewElement(current,name);
+ if(datatype == NX_CHAR){
+ newData = mxmlNewOpaque(dataNode,"");
+ return NX_OK;
+ } else {
+ typestring = buildTypeString(datatype,rank,dimensions);
+ if(typestring != NULL){
+ mxmlElementSetAttr(dataNode,TYPENAME,typestring);
+ free(typestring);
+ } else {
+ NXIReportError(NXpData,"Failed to allocate typestring");
+ return NX_ERROR;
+ }
+ newData = (mxml_node_t *)malloc(sizeof(mxml_node_t));
+ if(!newData){
+ NXIReportError(NXpData,"Failed to allocate space for dataset");
+ return NX_ERROR;
+ }
+ memset(newData,0,sizeof(mxml_node_t));
+ mxmlAdd(dataNode, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, newData);
+ newData->type = MXML_CUSTOM;
+ newData->value.custom.data = createNXDataset(rank,datatype,dimensions);
+ if(!newData->value.custom.data){
+ NXIReportError(NXpData,"Failed to allocate space for dataset");
+ return NX_ERROR;
+ }
+ newData->value.custom.destroy = destroyDataset;
+ }
+ return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+static mxml_node_t *searchSDSLinks(pXMLNexus xmlHandle, CONSTCHAR *name){
+ mxml_node_t *linkNode = NULL;
+ mxml_node_t *current;
+ mxml_node_t *test = NULL;
+ const char *linkTarget;
+
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+ linkNode = current;
+ while((linkNode = mxmlFindElement(linkNode,current,"NAPIlink",NULL,NULL,
+ MXML_DESCEND_FIRST)) != NULL){
+ linkTarget = mxmlElementGetAttr(linkNode,"target");
+ test = getLinkTarget(xmlHandle,linkTarget);
+ if(test != NULL){
+ if(strcmp(test->value.element.name,name) == 0){
+ return test;
+ }
+ }
+ }
+ return NULL;
+}
+/*-----------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXopendata (NXhandle fid, CONSTCHAR *name){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *dataNode = NULL;
+ char error[1024];
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ /*
+ silently fix this
+ */
+ xmlHandle->stackPointer--;
+ if(xmlHandle->stackPointer < 0){
+ xmlHandle->stackPointer = 0;
+ }
+ }
+
+ dataNode = mxmlFindElement(xmlHandle->stack[xmlHandle->stackPointer].current,
+ xmlHandle->stack[xmlHandle->stackPointer].current,
+ name,
+ NULL,
+ NULL,
+ MXML_DESCEND_FIRST);
+ if(dataNode == NULL){
+ dataNode = searchSDSLinks(xmlHandle,name);
+ }
+ if(!dataNode){
+ snprintf(error,1023,"Failed to open dataset %s",name);
+ NXIReportError(NXpData,error);
+ return NX_ERROR;
+ }
+ xmlHandle->stackPointer++;
+ xmlHandle->stack[xmlHandle->stackPointer].current = dataNode;
+ xmlHandle->stack[xmlHandle->stackPointer].currentChild = NULL;
+ xmlHandle->stack[xmlHandle->stackPointer].currentAttribute = 0;
+ return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXclosedata (NXhandle fid){
+ pXMLNexus xmlHandle = NULL;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ if(xmlHandle->stackPointer > 0){
+ xmlHandle->stackPointer--;
+ }
+ return NX_OK;
+ }
+ return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+static mxml_node_t *findData(mxml_node_t *node){
+ mxml_node_t *baby = node;
+
+ while( (baby = mxmlWalkNext(baby,node,MXML_DESCEND_FIRST)) != NULL){
+ if(baby->type == MXML_OPAQUE || baby->type == MXML_CUSTOM){
+ return baby;
+ }
+ }
+ return NULL;
+}
+/*------------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXputdata (NXhandle fid, void *data){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *userData = NULL;
+ mxml_node_t *current = NULL;
+ pNXDS dataset;
+ int length;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ NXIReportError(NXpData,"No dataset open");
+ return NX_ERROR;
+ }
+
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+ userData = findData(current);
+ assert(userData != NULL);
+ if(userData->type == MXML_OPAQUE){
+ /*
+ text data
+ */
+ mxmlSetOpaque(userData,(const char *)data);
+ } else {
+ dataset = (pNXDS)userData->value.custom.data;
+ assert(dataset);
+ length = getNXDatasetByteLength(dataset);
+ memcpy(dataset->u.ptr,data,length);
+ }
+ return NX_OK;
+}
+/*------------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXgetdata (NXhandle fid, void *data){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *userData = NULL;
+ mxml_node_t *current = NULL;
+ pNXDS dataset;
+ int length;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ NXIReportError(NXpData,"No dataset open");
+ return NX_ERROR;
+ }
+
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+ userData = findData(current);
+ assert(userData != NULL);
+ if(userData->type == MXML_OPAQUE){
+ /*
+ text data
+ */
+ strcpy((char *)data,userData->value.opaque);
+ } else {
+ dataset = (pNXDS)userData->value.custom.data;
+ assert(dataset);
+ length = getNXDatasetByteLength(dataset);
+ memcpy(data,dataset->u.ptr,length);
+ }
+ return NX_OK;
+}
+/*------------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXgetinfo (NXhandle fid, int *rank,
+ int dimension[], int *iType){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *userData = NULL;
+ mxml_node_t *current = NULL;
+ pNXDS dataset;
+ int myRank, i;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ NXIReportError(NXpData,"No dataset open");
+ return NX_ERROR;
+ }
+
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+ userData = findData(current);
+ assert(userData != NULL);
+ if(userData->type == MXML_OPAQUE){
+ /*
+ text data
+ */
+ *rank = 1;
+ *iType = NX_CHAR;
+ dimension[0]= strlen(userData->value.opaque) +1;
+ } else {
+ dataset = (pNXDS)userData->value.custom.data;
+ assert(dataset);
+ myRank = getNXDatasetRank(dataset);
+ *rank = myRank;
+ *iType = getNXDatasetType(dataset);
+ for(i = 0; i < myRank; i++){
+ dimension[i] = getNXDatasetDim(dataset,i);
+ }
+ }
+ return NX_OK;
+}
+/*---------------------------------------------------------------------
+ clone the dataset and set the data pointer. This in order to use
+ the addressing and type conversion implemented in nxdataset
+---------------------------------------------------------------------*/
+static pNXDS makeSlabData(pNXDS dataset, void *data, int size[]){
+ pNXDS slabData = NULL;
+ int rank, i;
+
+ slabData = (pNXDS)malloc(sizeof(NXDS));
+ if(slabData == NULL){
+ return NULL;
+ }
+
+ rank = getNXDatasetRank(dataset);
+ slabData->rank = rank;
+ slabData->dim = (int *)malloc(rank*sizeof(int));
+ for(i = 0; i < rank; i++){
+ slabData->dim[i] = size[i];
+ }
+ slabData->type = getNXDatasetType(dataset);
+ slabData->u.ptr = data;
+ slabData->magic = dataset->magic;
+ return slabData;
+}
+/*--------------------------------------------------------------------
+ This goes by recursion
+----------------------------------------------------------------------*/
+static void putSlabData(pNXDS dataset, pNXDS slabData, int dim,
+ int start[],
+ int sourcePos[],int targetPos[]){
+ int i, rank, length;
+
+ rank = getNXDatasetRank(slabData);
+ length = getNXDatasetDim(slabData,dim);
+ if(dim != rank-1){
+ for(i = 0; i < length; i++){
+ targetPos[dim] = start[dim] +i;
+ sourcePos[dim] = i;
+ putSlabData(dataset,slabData, dim+1,start,
+ sourcePos,targetPos);
+ }
+ } else {
+ for(i = 0; i < length; i++){
+ targetPos[dim] = start[dim] +i;
+ sourcePos[dim] = i;
+ putNXDatasetValue(dataset,targetPos,
+ getNXDatasetValue(slabData,sourcePos));
+ }
+ }
+}
+/*----------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXputslab (NXhandle fid, void *data,
+ int iStart[], int iSize[]){
+
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *userData = NULL;
+ mxml_node_t *current = NULL;
+ pNXDS dataset, slabData;
+ int sourcePos[NX_MAXRANK], targetPos[NX_MAXRANK];
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ NXIReportError(NXpData,"No dataset open");
+ return NX_ERROR;
+ }
+
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+ userData = findData(current);
+ assert(userData != NULL);
+ if(userData->type == MXML_OPAQUE){
+ NXIReportError(NXpData,"This API does not support slabs on text data");
+ return NX_ERROR;
+ }
+ dataset = (pNXDS)userData->value.custom.data;
+ assert(dataset);
+ slabData = makeSlabData(dataset, data, iSize);
+ if(slabData == NULL){
+ NXIReportError(NXpData,"Failed to allocate slab data");
+ return NX_ERROR;
+ }
+ putSlabData(dataset,slabData,0,iStart,sourcePos,targetPos);
+ free(slabData->dim);
+ free(slabData);
+
+ return NX_OK;
+}
+/*--------------------------------------------------------------------
+ This goes by recursion
+----------------------------------------------------------------------*/
+static void getSlabData(pNXDS dataset, pNXDS slabData, int dim,
+ int start[],
+ int sourcePos[],int targetPos[]){
+ int i, rank, length;
+
+ rank = getNXDatasetRank(slabData);
+ length = getNXDatasetDim(slabData,dim);
+ if(dim != rank-1){
+ for(i = 0; i < length; i++){
+ sourcePos[dim] = start[dim] +i;
+ targetPos[dim] = i;
+ getSlabData(dataset,slabData, dim+1,start,
+ sourcePos,targetPos);
+ }
+ } else {
+ for(i = 0; i < length; i++){
+ sourcePos[dim] = start[dim] +i;
+ targetPos[dim] = i;
+ putNXDatasetValue(slabData,targetPos,
+ getNXDatasetValue(dataset,sourcePos));
+ }
+ }
+}
+/*----------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXgetslab (NXhandle fid, void *data,
+ int iStart[], int iSize[]){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *userData = NULL;
+ mxml_node_t *current = NULL;
+ pNXDS dataset, slabData;
+ int sourcePos[NX_MAXRANK], targetPos[NX_MAXRANK];
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ NXIReportError(NXpData,"No dataset open");
+ return NX_ERROR;
+ }
+
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+ userData = findData(current);
+ assert(userData != NULL);
+ if(userData->type == MXML_OPAQUE){
+ NXIReportError(NXpData,"This API does not support slabs on text data");
+ return NX_ERROR;
+ }
+ dataset = (pNXDS)userData->value.custom.data;
+ assert(dataset);
+ slabData = makeSlabData(dataset, data, iSize);
+ if(slabData == NULL){
+ NXIReportError(NXpData,"Failed to allocate slab data");
+ return NX_ERROR;
+ }
+ getSlabData(dataset,slabData,0,iStart,sourcePos,targetPos);
+ free(slabData->dim);
+ free(slabData);
+
+ return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+static NXstatus CALLING_STYLE NXXsetnumberformat(NXhandle fid,
+ int type, char *format){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *current = NULL;
+ mxml_node_t *userData = NULL;
+ pNXDS dataset;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+ userData = findData(current);
+ assert(userData != NULL);
+ if(userData->type == MXML_OPAQUE){
+ return NX_OK;
+ }
+ dataset = (pNXDS)userData->value.custom.data;
+ assert(dataset);
+ if(dataset->format != NULL){
+ free(dataset->format);
+ }
+ dataset->format = strdup(format);
+ } else {
+ setNumberFormat(type, format);
+ }
+ return NX_OK;
+}
+/*============================ Attributes ============================*/
+static char *formatAttributeData(void *data, int datalen, int iType){
+ int intData = 0;
+ long iValue;
+ double dValue;
+ char type[20];
+ char *number;
+
+
+ if(iType == NX_CHAR){
+ return strdup((char *)data);
+ }
+
+ number = (char *)malloc(132*sizeof(char));
+ if(!number){
+ NXIReportError(NXpData,"Failed to allocate attribute number buffer");
+ return NULL;
+ }
+
+ if(datalen > 1){
+ return NULL;
+ }
+ type[0] = '\0';
+ switch(iType){
+ case NX_INT32:
+ iValue = ((int *)data)[0];
+ intData = 1;
+ strcpy(type,"NX_INT32:");
+ break;
+ case NX_UINT32:
+ iValue = ((unsigned int *)data)[0];
+ intData = 1;
+ strcpy(type,"NX_UINT32:");
+ break;
+ case NX_INT16:
+ iValue = ((short *)data)[0];
+ intData = 1;
+ strcpy(type,"NX_INT16:");
+ break;
+ case NX_UINT16:
+ iValue = ((unsigned short *)data)[0];
+ intData = 1;
+ strcpy(type,"NX_UINT16:");
+ break;
+ case NX_INT8:
+ iValue = (int)((char *)data)[0];
+ intData = 1;
+ strcpy(type,"NX_INT8:");
+ break;
+ case NX_UINT8:
+ intData = 1;
+ iValue = (int)((unsigned char *)data)[0];
+ strcpy(type,"NX_UINT8:");
+ break;
+ case NX_FLOAT32:
+ dValue = ((float *)data)[0];
+ strcpy(type,"NX_FLOAT32:");
+ intData = 0;
+ break;
+ case NX_FLOAT64:
+ dValue = ((double *)data)[0];
+ strcpy(type,"NX_FLOAT64:");
+ intData = 0;
+ break;
+ }
+ if(intData){
+ snprintf(number,79,"%s%d",type,iValue);
+ } else {
+ snprintf(number,79,"%s%f",type,dValue);
+ }
+ return number;
+}
+/*---------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXputattr (NXhandle fid, CONSTCHAR *name, void *data,
+ int datalen, int iType){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *current = NULL;
+ char *numberData = NULL;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ /*
+ global attribute
+ */
+ current = xmlHandle->stack[0].current;
+ } else {
+ /*
+ dataset attribute
+ */
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+ if(strcmp(name,TYPENAME) == 0){
+ NXIReportError(NXpData,"type is a reserved attribute name, rejected");
+ return NX_ERROR;
+ }
+ }
+
+ numberData = formatAttributeData(data,datalen,iType);
+ if(numberData == NULL){
+ NXIReportError(NXpData,"This API does not support non number arrays");
+ return NX_ERROR;
+ } else {
+ mxmlElementSetAttr(current,name,numberData);
+ free(numberData);
+ }
+ return NX_OK;
+}
+/*--------------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXgetattr (NXhandle fid, char *name,
+ void *data, int* datalen, int* iType){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *current = NULL;
+ const char *attribute = NULL;
+ char error[1024];
+ char *attData = NULL;
+ int iValue, nx_type;
+ float fValue;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ /*
+ global attribute
+ */
+ current = xmlHandle->stack[0].current;
+ } else {
+ /*
+ dataset attribute
+ */
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+ }
+
+ attribute = mxmlElementGetAttr(current,name);
+ if(!attribute){
+ snprintf(error,1023,"Attribute %s not found", name);
+ NXIReportError(NXpData,error);
+ return NX_ERROR;
+ }
+ nx_type = translateTypeCode((char *)attribute);
+ if(nx_type < 0) {
+ /*
+ no type code == text attribute
+ */
+ nx_type = NX_CHAR;
+ } else {
+ /*
+ We need to find the number after the type code. However, there is
+ the complication of the datatype type attribute ...
+ */
+ if(strcmp(name,TYPENAME) == 0){
+ nx_type = NX_CHAR;
+ } else {
+ attData = strchr(attribute,(int)':');
+ if(attData == NULL){
+ NXIReportError(NXpData,"ERROR: bad attribute string, : missing");
+ return NX_ERROR;
+ }
+ attData++;
+ }
+ }
+ *iType = nx_type;
+ switch(nx_type){
+ case NX_CHAR:
+ strncpy((char *)data, attribute, *datalen);
+ *datalen = strlen(attribute);
+ *iType = NX_CHAR;
+ break;
+ case NX_INT32:
+ ((int *)data)[0] = atoi(attData);
+ *datalen = 1;
+ break;
+ case NX_UINT32:
+ ((unsigned int *)data)[0] = atoi(attData);
+ *datalen = 1;
+ break;
+ case NX_INT16:
+ ((short *)data)[0] = atoi(attData);
+ *datalen = 1;
+ break;
+ case NX_UINT16:
+ ((unsigned short *)data)[0] = atoi(attData);
+ *datalen = 1;
+ break;
+ case NX_INT8:
+ ((char *)data)[0] = atoi(attData);
+ *datalen = 1;
+ break;
+ case NX_UINT8:
+ ((unsigned char *)data)[0] = atoi(attData);
+ *datalen = 1;
+ break;
+ case NX_FLOAT32:
+ ((float *)data)[0] = atof(attData);
+ *datalen = 1;
+ break;
+ case NX_FLOAT64:
+ ((double *)data)[0] = atof(attData);
+ *datalen = 1;
+ break;
+ }
+
+ return NX_OK;
+}
+/*====================== search functions =================================*/
+NXstatus CALLING_STYLE NXXgetnextentry (NXhandle fid,NXname name,
+ NXname nxclass, int *datatype){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *next = NULL, *userData;
+ int stackPtr;
+ const char *target = NULL, *attname = NULL;
+ pNXDS dataset;
+ char pBueffel[256];
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ NXIReportError(NXpData,"Cannot search datasets");
+ return NX_ERROR;
+ }
+
+ stackPtr = xmlHandle->stackPointer;
+ if(xmlHandle->stack[stackPtr].currentChild == NULL){
+ /*
+ initialization of search
+ */
+ xmlHandle->stack[stackPtr].currentChild =
+ xmlHandle->stack[stackPtr].current->child;
+ } else {
+ /*
+ proceed
+ */
+ xmlHandle->stack[stackPtr].currentChild =
+ xmlHandle->stack[stackPtr].currentChild->next;
+ }
+ next = xmlHandle->stack[stackPtr].currentChild;
+ if(next == NULL){
+ return NX_EOD;
+ }
+ if(strcmp(next->value.element.name,"NAPIlink") == 0){
+ target = mxmlElementGetAttr(next,"target");
+ if(target == NULL){
+ NXIReportError(NXpData,"Corrupted file, NAPIlink without target");
+ return NX_ERROR;
+ }
+ next = getLinkTarget(xmlHandle,target);
+ if(next == NULL){
+ NXIReportError(NXpData,"Corrupted file, broken link");
+ return NX_ERROR;
+ }
+ }
+
+ if(isDataNode(next)){
+ strcpy(name,next->value.element.name);
+ strcpy(nxclass,"SDS");
+ userData = findData(next);
+ if(userData == NULL){
+ snprintf(pBueffel,255,"Corrupted file, userData for %s not found",
+ name);
+ NXIReportError(NXpData,pBueffel);
+ return NX_ERROR;
+ }
+ if(userData->type == MXML_OPAQUE){
+ *datatype = NX_CHAR;
+ } else {
+ dataset = (pNXDS)userData->value.custom.data;
+ assert(dataset);
+ *datatype = getNXDatasetType(dataset);
+ }
+ } else {
+ strcpy(nxclass,next->value.element.name);
+ attname = mxmlElementGetAttr(next,"name");
+ strcpy(name,attname);
+ }
+ return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+NX_EXTERNAL NXstatus CALLING_STYLE NXXinitgroupdir(NXhandle fid){
+ pXMLNexus xmlHandle = NULL;
+ int stackPtr;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ NXIReportError(NXpData,"Cannot search datasets");
+ return NX_ERROR;
+ }
+
+ stackPtr = xmlHandle->stackPointer;
+ xmlHandle->stack[stackPtr].currentChild = NULL;
+ return NX_OK;
+}
+/*-------------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXgetnextattr (NXhandle fid, NXname pName,
+ int *iLength, int *iType){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *current = NULL;
+ int stackPtr, currentAtt, nx_type;
+ char *attVal;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ /*
+ dataset attribute
+ */
+ stackPtr = xmlHandle->stackPointer;
+ } else {
+ /*
+ global attribute
+ */
+ stackPtr = 0;
+ }
+
+ current = xmlHandle->stack[stackPtr].current;
+ currentAtt = xmlHandle->stack[stackPtr].currentAttribute;
+ if(currentAtt >=
+ current->value.element.num_attrs ){
+ xmlHandle->stack[stackPtr].currentAttribute = 0;
+ return NX_EOD;
+ }
+
+ /*
+ hide type attribute
+ */
+ if(strcmp(current->value.element.attrs[currentAtt].name,TYPENAME) == 0){
+ xmlHandle->stack[stackPtr].currentAttribute++;
+ return NXXgetnextattr(fid,pName,iLength,iType);
+ }
+
+ strcpy(pName,current->value.element.attrs[currentAtt].name);
+ attVal = current->value.element.attrs[currentAtt].value;
+ nx_type = translateTypeCode((char *)attVal);
+ if(nx_type < 0 || strcmp(pName,TYPENAME) == 0){
+ /*
+ no type == NX_CHAR
+ */
+ *iLength = strlen(attVal);
+ *iType = NX_CHAR;
+ } else {
+ *iLength = 1;
+ *iType = nx_type;
+ }
+
+ xmlHandle->stack[stackPtr].currentAttribute++;
+ return NX_OK;
+}
+/*-------------------------------------------------------------------------*/
+NX_EXTERNAL NXstatus CALLING_STYLE NXXinitattrdir(NXhandle fid){
+ pXMLNexus xmlHandle = NULL;
+ int stackPtr;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ /*
+ dataset attribute
+ */
+ stackPtr = xmlHandle->stackPointer;
+ } else {
+ /*
+ global attribute
+ */
+ stackPtr = 0;
+ }
+
+ xmlHandle->stack[stackPtr].currentAttribute = 0;
+ return NX_OK;
+}
+/*-------------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXgetgroupinfo (NXhandle fid, int *iN,
+ NXname pName, NXname pClass){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *child = NULL;
+ mxml_node_t *current = NULL;
+ const char *nameAtt = NULL;
+ int childCount;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ NXIReportError(NXpData,"No group open");
+ return NX_ERROR;
+ }
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+
+ nameAtt = mxmlElementGetAttr(current,"name");
+ if(nameAtt != NULL){
+ strcpy(pName,nameAtt);
+ }
+ strcpy(pClass,current->value.element.name);
+
+ childCount = 0;
+ child = current->child;
+ while(child != NULL){
+ childCount++;
+ child = child->next;
+ }
+ *iN = childCount;
+ return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXgetattrinfo (NXhandle fid, int *iN){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *current = NULL;
+ int stackPtr, currentAtt;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ /*
+ dataset attribute
+ */
+ stackPtr = xmlHandle->stackPointer;
+ } else {
+ /*
+ global attribute
+ */
+ stackPtr = 0;
+ }
+
+ current = xmlHandle->stack[stackPtr].current;
+ /*
+ hide type attribute
+ */
+ if(mxmlElementGetAttr(current,TYPENAME) != NULL){
+ *iN = current->value.element.num_attrs -1;
+ } else {
+ *iN = current->value.element.num_attrs;
+ }
+ return NX_OK;
+}
+/*================= Linking functions =================================*/
+static int countPathChars(mxml_node_t *path[], int stackPtr){
+ int count = 1;
+ const char *name = NULL;
+
+ while(stackPtr >= 0) {
+ if(isDataNode(path[stackPtr])){
+ count += strlen(path[stackPtr]->value.element.name);
+ } else {
+ name = mxmlElementGetAttr(path[stackPtr],"name");
+ if(name != NULL){
+ count += strlen(name);
+ }
+ }
+ stackPtr--;
+ count += 1;
+ }
+ return count;
+}
+/*-------------------------------------------------------------------*/
+static char *buildPathString(mxml_node_t *path[], int stackPtr){
+ int count = 0;
+ const char *name = NULL;
+ char *pathString = NULL;
+
+ count = countPathChars(path,stackPtr);
+ pathString = (char *)malloc((count+10)*sizeof(char));
+ if(pathString == NULL){
+ return NULL;
+ }
+ memset(pathString,0,(count+10)*sizeof(char));
+
+ while(stackPtr >= 0) {
+ if(isDataNode(path[stackPtr])){
+ strcat(pathString,"/");
+ strcat(pathString,path[stackPtr]->value.element.name);
+ } else {
+ name = mxmlElementGetAttr(path[stackPtr],"name");
+ if(name != NULL){
+ strcat(pathString,"/");
+ strcat(pathString,name);
+ }
+ }
+ stackPtr--;
+ }
+ return pathString;
+}
+/*--------------------------------------------------------------------*/
+static char *findLinkPath(mxml_node_t *node){
+ mxml_node_t **path = NULL;
+ int stackPtr;
+ mxml_node_t *current = NULL;
+ char *pathString = NULL, *result = NULL;
+ int count;
+
+ path = (mxml_node_t **)malloc(NXMAXSTACK*sizeof(mxml_node_t *));
+ if(path == NULL){
+ NXIReportError(NXpData,"ERROR: out of memory follwoing link path");
+ return NULL;
+ }
+ memset(path,0,NXMAXSTACK*sizeof(mxml_node_t *));
+
+ /*
+ first path: walk up the tree untill NXroot is found
+ */
+ current = node;
+ stackPtr = 0;
+ while(current != NULL &&
+ strcmp(current->value.element.name,"NXroot") != 0){
+ path[stackPtr] = current;
+ stackPtr++;
+ current = current->parent;
+ }
+ stackPtr--;
+
+ /*
+ path now contains the nodes to the root node in reverse order.
+ From this build the path string
+ */
+ result = buildPathString(path,stackPtr);
+ free(path);
+ return result;
+}
+/*--------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXgetdataID (NXhandle fid, NXlink* sRes){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *current = NULL;
+ char *linkPath = NULL;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(!isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ return NX_ERROR;
+ }
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+
+ linkPath = findLinkPath(current);
+ if(!linkPath){
+ NXIReportError(NXpData,"Failed to allocate link path string");
+ return NX_ERROR;
+ }
+ strncpy(sRes->targetPath,linkPath,1023);
+ free(linkPath);
+ return NX_OK;
+}
+/*--------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXgetgroupID (NXhandle fid, NXlink* sRes){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *current = NULL;
+ char *linkPath = NULL;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ NXIReportError(NXpData,"No group open");
+ return NX_ERROR;
+ }
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+
+ if(xmlHandle->stackPointer == 0){
+ return NX_ERROR;
+ }
+
+ linkPath = findLinkPath(current);
+ if(!linkPath){
+ NXIReportError(NXpData,"Failed to allocate link path string");
+ return NX_ERROR;
+ }
+ strncpy(sRes->targetPath,linkPath,1023);
+ free(linkPath);
+ return NX_OK;
+}
+/*-----------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXmakelink (NXhandle fid, NXlink* sLink){
+ pXMLNexus xmlHandle = NULL;
+ mxml_node_t *current = NULL, *linkNode = NULL;
+ mxml_node_t *linkedNode = NULL;
+
+ xmlHandle = (pXMLNexus)fid;
+ assert(xmlHandle);
+
+ if(isDataNode(xmlHandle->stack[xmlHandle->stackPointer].current)){
+ NXIReportError(NXpData,"No group to link to open");
+ return NX_ERROR;
+ }
+ current = xmlHandle->stack[xmlHandle->stackPointer].current;
+ linkNode = mxmlNewElement(current,"NAPIlink");
+ if(!linkNode){
+ NXIReportError(NXpData,"Failed to allocate new link element");
+ return NX_ERROR;
+ }
+ mxmlElementSetAttr(linkNode,"target",sLink->targetPath);
+ linkedNode = getLinkTarget(xmlHandle,sLink->targetPath);
+ if(linkedNode != NULL){
+ mxmlElementSetAttr(linkedNode,"target",sLink->targetPath);
+ }
+ return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+NXstatus CALLING_STYLE NXXsameID (NXhandle fileid, NXlink* pFirstID,
+ NXlink* pSecondID){
+ if(strcmp(pFirstID->targetPath,pSecondID->targetPath) == 0) {
+ return NX_OK;
+ } else {
+ return NX_ERROR;
+ }
+}
+/*--------------------------------------------------------------------*/
+int NXXcompress(NXhandle fid, int comp){
+ NXIReportError(NXpData,"NXcompress is deprecated, IGNORED");
+ return NX_OK;
+}
+/*----------------------------------------------------------------------*/
+void NXXassignFunctions(pNexusFunction fHandle){
+ fHandle->nxclose=NXXclose;
+ fHandle->nxflush=NXXflush;
+ fHandle->nxmakegroup=NXXmakegroup;
+ fHandle->nxopengroup=NXXopengroup;
+ fHandle->nxclosegroup=NXXclosegroup;
+ fHandle->nxmakedata=NXXmakedata;
+ fHandle->nxcompmakedata=NXXcompmakedata;
+ fHandle->nxcompress=NXXcompress;
+ fHandle->nxopendata=NXXopendata;
+ fHandle->nxclosedata=NXXclosedata;
+ fHandle->nxputdata=NXXputdata;
+ fHandle->nxputattr=NXXputattr;
+ fHandle->nxputslab=NXXputslab;
+ fHandle->nxgetdataID=NXXgetdataID;
+ fHandle->nxmakelink=NXXmakelink;
+ fHandle->nxgetdata=NXXgetdata;
+ fHandle->nxgetinfo=NXXgetinfo;
+ fHandle->nxgetnextentry=NXXgetnextentry;
+ fHandle->nxgetslab=NXXgetslab;
+ fHandle->nxgetnextattr=NXXgetnextattr;
+ fHandle->nxgetattr=NXXgetattr;
+ fHandle->nxgetattrinfo=NXXgetattrinfo;
+ fHandle->nxgetgroupID=NXXgetgroupID;
+ fHandle->nxgetgroupinfo=NXXgetgroupinfo;
+ fHandle->nxsameID=NXXsameID;
+ fHandle->nxinitgroupdir=NXXinitgroupdir;
+ fHandle->nxinitattrdir=NXXinitattrdir;
+ fHandle->nxsetnumberformat=NXXsetnumberformat;
+}
+
diff --git a/tasdrive.c b/tasdrive.c
index 4a230630..27a44723 100644
--- a/tasdrive.c
+++ b/tasdrive.c
@@ -29,7 +29,7 @@
#define ACH 11
/*============== Drivable Interface functions =====================*/
-static int TASSetValue(void *pData, SConnection *pCon,
+static long TASSetValue(void *pData, SConnection *pCon,
float value){
ptasMot self = (ptasMot)pData;
assert(self);
@@ -142,7 +142,8 @@ static float TASQMGetValue(void *pData, SConnection *pCon){
if(status != 1){
return -999.99;
}
- status = calcTasPowderPosition(&self->math->machine, angles, &self->math->current);
+ status = calcTasPowderPosition(&self->math->machine,
+ angles, &self->math->current);
if(status < 0){
SCWrite(pCon,"ERROR: out of memory calculating Q-E variables",eError);
return -999.99;
@@ -176,7 +177,7 @@ static int TASHalt(void *pData){
}
/*---------------------------------------------------------------------------*/
static int startMotors(ptasMot self, tasAngles angles,
- SConnection *pCon){
+ SConnection *pCon, int driveQ){
float val;
double curve;
int status;
@@ -276,6 +277,9 @@ static int startMotors(ptasMot self, tasAngles angles,
}
}
}
+ if(driveQ == 0){
+ return OKOK;
+ }
/*
crystal
@@ -319,39 +323,95 @@ static int startMotors(ptasMot self, tasAngles angles,
self->math->mustDrive = 0;
return OKOK;
}
+/*---------------------------------------------------------------------------*/
+static int checkQMotorLimits(ptasMot self, SConnection *pCon,
+ tasAngles angles){
+ int status, retVal = 1;
+ char error[131];
+ char pBueffel[256];
+
+ status = self->math->motors[A3]->pDrivInt->CheckLimits(self->math->motors[A3],
+ angles.a3,
+ error,
+ 131);
+ if(status != 1) {
+ retVal = 0;
+ snprintf(pBueffel,256,"ERROR: limit violation an a3: %s", error);
+ SCWrite(pCon,pBueffel,eError);
+ }
+
+ status = self->math->motors[A4]->pDrivInt->CheckLimits(self->math->motors[A4],
+ angles.sample_two_theta,
+ error,
+ 131);
+ if(status != 1) {
+ retVal = 0;
+ snprintf(pBueffel,256,"ERROR: limit violation an a4: %s", error);
+ SCWrite(pCon,pBueffel,eError);
+ }
+
+ status = self->math->motors[A3]->pDrivInt->CheckLimits(self->math->motors[SGU],
+ angles.sgu,
+ error,
+ 131);
+ if(status != 1) {
+ retVal = 0;
+ snprintf(pBueffel,256,"ERROR: limit violation an SGU: %s", error);
+ SCWrite(pCon,pBueffel,eError);
+ }
+
+ status = self->math->motors[SGL]->pDrivInt->CheckLimits(self->math->motors[SGL],
+ angles.sgl,
+ error,
+ 131);
+ if(status != 1) {
+ retVal = 0;
+ snprintf(pBueffel,256,"ERROR: limit violation an SGL: %s", error);
+ SCWrite(pCon,pBueffel,eError);
+ }
+ return retVal;
+}
/*-----------------------------------------------------------------------------*/
static int calculateAndDrive(ptasMot self, SConnection *pCon){
tasAngles angles;
- int status;
+ int status, driveQ = 1;
+ if(self->math->ubValid == 0){
+ SCWrite(pCon,"WARNING: UB matrix invalid",eWarning);
+ }
status = calcAllTasAngles(&self->math->machine, self->math->target,
&angles);
+ self->math->mustDrive = 0;
switch(status){
case ENERGYTOBIG:
SCWrite(pCon,"ERROR: desired energy to big",eError);
- self->math->mustDrive = 0;
return HWFault;
break;
-
case UBNOMEMORY:
SCWrite(pCon,"ERROR: out of memory calculating angles",eError);
- self->math->mustDrive = 0;
- return HWFault;
+ driveQ = 0;
break;
case BADRMATRIX:
SCWrite(pCon,"ERROR: bad crystallographic parameters or bad UB",eError);
- self->math->mustDrive = 0;
- return HWFault;
+ driveQ = 0;
+ break;
+ case BADUBORQ:
+ SCWrite(pCon,"ERROR: bad UB matrix or bad Q-vector",eError);
+ driveQ = 0;
break;
case TRIANGLENOTCLOSED:
SCWrite(pCon,"ERROR: cannot close scattering triangle",eError);
- self->math->mustDrive = 0;
- return HWFault;
+ driveQ = 0;
break;
- default:
- return startMotors(self,angles,pCon);
}
- return HWFault;
+ if(!checkQMotorLimits(self,pCon,angles)){
+ driveQ = 0;
+ }
+
+ if(driveQ == 0){
+ SCWrite(pCon,"WARNING: NOT driving Q-vector because of errors",eError);
+ }
+ return startMotors(self,angles,pCon, driveQ);
}
/*-----------------------------------------------------------------------------*/
static int checkMotors(ptasMot self, SConnection *pCon){
diff --git a/tasub.c b/tasub.c
index b54f0079..a1419396 100644
--- a/tasub.c
+++ b/tasub.c
@@ -53,6 +53,7 @@ static void saveReflections(ptasUB self, char *name, FILE *fd){
/*-------------------------------------------------------------------*/
static int tasUBSave(void *pData, char *name, FILE *fd){
ptasUB self = (ptasUB)pData;
+ tasReflection r;
if(self == NULL){
return 0;
@@ -83,8 +84,16 @@ static int tasUBSave(void *pData, char *name, FILE *fd){
name,
self->target.qh, self->target.qk, self->target.ql, self->target.qm,
self->target.ki, self->target.kf);
- fprintf(fd,"%s setidx %d %d\n",
- name, self->r1, self->r2);
+ r = self->r1;
+ fprintf(fd,"%s r1 %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n",
+ name, r.qe.qh, r.qe.qk, r.qe.ql, r.angles.a3, r.angles.sample_two_theta,
+ r.angles.sgu, r.angles.sgl,
+ KtoEnergy(r.qe.ki), KtoEnergy(r.qe.kf));
+ r = self->r2;
+ fprintf(fd,"%s r2 %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n",
+ name, r.qe.qh, r.qe.qk, r.qe.ql, r.angles.a3, r.angles.sample_two_theta,
+ r.angles.sgu, r.angles.sgl,
+ KtoEnergy(r.qe.ki), KtoEnergy(r.qe.kf));
fprintf(fd,"%s update\n", name);
return 1;
}
@@ -455,6 +464,8 @@ static int tasReadCell(SConnection *pCon, ptasUB self, int argc, char *argv[]){
SCWrite(pCon,pBueffel,eError);
return 0;
}
+ self->ubValid = 0;
+ SCWrite(pCon,"WARNING: UB is now invalid",eWarning);
SCparChange(pCon);
SCSendOK(pCon);
return 1;
@@ -477,8 +488,7 @@ static void clearReflections(ptasUB self){
LLDnodeDelete(self->reflectionList);
status = LLDnodePtr2Next(self->reflectionList);
}
- self->r1 = -1;
- self->r2 = -1;
+ self->ubValid = 0;
}
/*------------------------------------------------------------------*/
static void listReflections(ptasUB self, SConnection *pCon){
@@ -621,6 +631,84 @@ static int addReflection(ptasUB self, SicsInterp *pSics,
SCparChange(pCon);
return 1;
}
+/*------------------------------------------------------------------------------*/
+static int readReflection(SConnection *pCon, SicsInterp *pSics,
+ ptasReflection res,
+ int argc, char *argv[]){
+ tasReflection r;
+ int status;
+ char pBueffel[256];
+
+ if(!SCMatchRights(pCon,usUser)){
+ return 0;
+ }
+
+ if(argc < 11){
+ SCWrite(pCon,"ERROR: not enough parameters to read reflection",eError);
+ return 0;
+ }
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[2],&r.qe.qh);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[3],&r.qe.qk);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[3]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[4],&r.qe.ql);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[4]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[5],&r.angles.a3);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[5]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[6],&r.angles.sample_two_theta);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[6]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[7],&r.angles.sgu);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[7]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[8],&r.angles.sgl);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[8]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[9],&r.qe.ki);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[9]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ r.qe.ki = energyToK(r.qe.ki);
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[10],&r.qe.kf);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[10]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ r.qe.kf = energyToK(r.qe.kf);
+ if(ABS(r.qe.ki - r.qe.kf) > .01) {
+ SCWrite(pCon,"WARNING: KI != KF!",eWarning);
+ }
+ *res = r;
+ return 1;
+}
/*-----------------------------------------------------------------*/
int findReflection(int list, int idx, ptasReflection r){
int count = 0;
@@ -642,7 +730,7 @@ static void listUB(ptasUB self , SConnection *pCon){
Tcl_DString list;
char pBueffel[255];
int i;
-
+ tasReflection r;
Tcl_DStringInit(&list);
if(self->machine.UB == NULL){
@@ -658,9 +746,32 @@ static void listUB(ptasUB self , SConnection *pCon){
Tcl_DStringAppend(&list,pBueffel,-1);
}
}
- snprintf(pBueffel,255,"UB generated from reflections %d and %d in list\n",
- self->r1, self->r2);
+ snprintf(pBueffel,255,"UB generated from reflections:\n");
Tcl_DStringAppend(&list,pBueffel,-1);
+ snprintf(pBueffel,255,
+ " QH QK QL A3 A4 SGU SGL EI EF\n");
+ Tcl_DStringAppend(&list,pBueffel,-1);
+ r = self->r1;
+ snprintf(pBueffel,255,
+ " %8.4f %8.4f %8.4f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n",
+ r.qe.qh, r.qe.qk, r.qe.ql, r.angles.a3,
+ r.angles.sample_two_theta, r.angles.sgu, r.angles.sgl,
+ KtoEnergy(r.qe.ki), KtoEnergy(r.qe.kf));
+ Tcl_DStringAppend(&list,pBueffel,-1);
+ r = self->r2;
+ snprintf(pBueffel,255,
+ " %8.4f %8.4f %8.4f %7.2f %7.2f %6.2f %6.2f %6.2f %6.2f\n",
+ r.qe.qh, r.qe.qk, r.qe.ql, r.angles.a3,
+ r.angles.sample_two_theta, r.angles.sgu, r.angles.sgl,
+ KtoEnergy(r.qe.ki), KtoEnergy(r.qe.kf));
+ Tcl_DStringAppend(&list,pBueffel,-1);
+ snprintf(pBueffel,255,"Plane Normal: %8.4f %8.4f %8.4f\n",
+ self->machine.planeNormal[0][0], self->machine.planeNormal[1][0],
+ self->machine.planeNormal[2][0]);
+ Tcl_DStringAppend(&list,pBueffel,-1);
+ if(self->ubValid == 0){
+ Tcl_DStringAppend(&list,"WARNING: UB matrix is invalid\n",-1);
+ }
SCWrite(pCon,Tcl_DStringValue(&list),eValue);
Tcl_DStringFree(&list);
}
@@ -723,7 +834,7 @@ static void listDiagnostik(ptasUB self, SConnection *pCon){
/*------------------------------------------------------------------*/
static int calcUB(ptasUB self, SConnection *pCon, SicsInterp *pSics,
int argc, char *argv[]){
- int idx, status;
+ int idx1, idx2, status;
tasReflection r1, r2;
char pBueffel[256];
MATRIX UB = NULL;
@@ -739,32 +850,32 @@ static int calcUB(ptasUB self, SConnection *pCon, SicsInterp *pSics,
return 0;
}
- status = Tcl_GetInt(InterpGetTcl(pSics),argv[2],&idx);
+ status = Tcl_GetInt(InterpGetTcl(pSics),argv[2],&idx1);
if(status != TCL_OK){
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
- status = findReflection(self->reflectionList, idx-1,&r1);
+ idx1--;
+ status = findReflection(self->reflectionList, idx1,&r1);
if(status != 1){
- snprintf(pBueffel,255,"ERROR: cannot find reflection with index %d",idx);
+ snprintf(pBueffel,255,"ERROR: cannot find reflection with index %d",idx1+1);
SCWrite(pCon,pBueffel,eError);
return 0;
}
- self->r1 = idx;
- status = Tcl_GetInt(InterpGetTcl(pSics),argv[3],&idx);
+ status = Tcl_GetInt(InterpGetTcl(pSics),argv[3],&idx2);
if(status != TCL_OK){
snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[3]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
- status = findReflection(self->reflectionList, idx-1,&r2);
+ idx2--;
+ status = findReflection(self->reflectionList, idx2,&r2);
if(status != 1){
- snprintf(pBueffel,255,"ERROR: cannot find reflection with index %d",idx);
+ snprintf(pBueffel,255,"ERROR: cannot find reflection with index %d",idx2+1);
SCWrite(pCon,pBueffel,eError);
return 0;
}
- self->r2 = idx;
UB = calcTasUBFromTwoReflections(self->cell,r1,r2,&status);
if(UB == NULL){
@@ -778,6 +889,10 @@ static int calcUB(ptasUB self, SConnection *pCon, SicsInterp *pSics,
}
return 0;
}
+ if(mat_det(UB) < .000001){
+ SCWrite(pCon,"ERROR: invalid UB matrix, check reflections",eError);
+ return 0;
+ }
if(self->machine.UB != NULL){
mat_free(self->machine.UB);
}
@@ -786,6 +901,9 @@ static int calcUB(ptasUB self, SConnection *pCon, SicsInterp *pSics,
}
self->machine.UB = UB;
self->machine.planeNormal = calcPlaneNormal(r1,r2);
+ self->r1 = r1;
+ self->r2 = r2;
+ self->ubValid = 1;
listUB(self,pCon);
listDiagnostik(self,pCon);
SCparChange(pCon);
@@ -866,6 +984,74 @@ static int calcRefAngles(ptasUB self, SConnection *pCon,
return 1;
}
/*------------------------------------------------------------------*/
+static int calcQFromAngles(ptasUB self, SConnection *pCon,
+ SicsInterp *pSics,
+ int argc, char *argv[]){
+ tasQEPosition q;
+ tasAngles angles;
+ char pBueffel[256];
+ int status;
+
+ if(argc < 8){
+ SCWrite(pCon,"ERROR: need a2, a3, a4, sgu, sgl, a6 for calculation",
+ eError);
+ return 0;
+ }
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[2],
+ &angles.monochromator_two_theta);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[2]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[3],&angles.a3);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[3]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[4],&angles.sample_two_theta);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[4]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[5],&angles.sgu);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[5]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[6],&angles.sgl);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[6]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ status = Tcl_GetDouble(InterpGetTcl(pSics),argv[7],&angles.analyzer_two_theta);
+ if(status != TCL_OK){
+ snprintf(pBueffel,255,"ERROR: failed to convert %s to number",argv[7]);
+ SCWrite(pCon,pBueffel,eError);
+ return 0;
+ }
+ status = calcTasQEPosition(&self->machine,angles,&q);
+ switch(status){
+ case UBNOMEMORY:
+ SCWrite(pCon,"ERROR: Out of memory calculating angles",eError);
+ return 0;
+ break;
+ }
+
+ snprintf(pBueffel,255,"%8.4f %8.4f %8.4f %8.4f %8.4f",
+ q.qh,
+ q.qk,
+ q.ql,
+ KtoEnergy(q.ki),
+ KtoEnergy(q.kf));
+ SCWrite(pCon,pBueffel,eValue);
+ return 1;
+}
+/*------------------------------------------------------------------*/
static int setUB(SConnection *pCon, SicsInterp *pSics, ptasUB self,
int argc, char *argv[]){
double value;
@@ -953,28 +1139,13 @@ static int setUB(SConnection *pCon, SicsInterp *pSics, ptasUB self,
return 0;
}
self->machine.UB[2][2] = value;
+ self->ubValid = 1;
SCSendOK(pCon);
SCparChange(pCon);
return 1;
}
/*------------------------------------------------------------------*/
-static int setIDX(SConnection *pCon, SicsInterp *pSics, ptasUB self,
- int argc, char *argv[]){
- if(argc < 4) {
- SCWrite(pCon,"ERROR: not enough arguments to setidx", eError);
- return 0;
- }
-
- if(!SCMatchRights(pCon,usMugger)){
- return 0;
- }
- self->r1 = atoi(argv[2]);
- self->r2 = atoi(argv[3]);
- SCSendOK(pCon);
- return 1;
-}
-/*------------------------------------------------------------------*/
static int setNormal(SConnection *pCon, SicsInterp *pSics, ptasUB self,
int argc, char *argv[]){
double value;
@@ -1114,11 +1285,6 @@ static int deleteReflection(SConnection *pCon, SicsInterp *pSics,
SCWrite(pCon,pBueffel,eError);
return 0;
}
- if(idx == self->r1 || idx == self->r2) {
- SCWrite(pCon,"ERROR: I refuse to delete reflections used for current UB",
- eError);
- return 0;
- }
idx--;
status = LLDnodePtr2First(self->reflectionList);
while(status == 1){
@@ -1162,6 +1328,7 @@ int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,
} else if(strcmp(argv[1],"clear") == 0){
clearReflections(self);
clearReflections(self);
+ SCWrite(pCon,"WARNING: UB is now invalid",eWarning);
SCSendOK(pCon);
return 1;
} else if(strcmp(argv[1],"listref") == 0){
@@ -1174,20 +1341,24 @@ int TasUBWrapper(SConnection *pCon,SicsInterp *pSics, void *pData,
return 1;
} else if(strcmp(argv[1],"makeub") == 0){
return calcUB(self,pCon,pSics,argc,argv);
- } else if(strcmp(argv[1],"calcref") == 0){
+ } else if(strcmp(argv[1],"calcang") == 0){
return calcRefAngles(self,pCon,pSics,argc,argv);
+ } else if(strcmp(argv[1],"calcqe") == 0){
+ return calcQFromAngles(self,pCon,pSics,argc,argv);
} else if(strcmp(argv[1],"setub") == 0){
return setUB(pCon,pSics,self,argc,argv);
} else if(strcmp(argv[1],"setnormal") == 0){
return setNormal(pCon,pSics,self,argc,argv);
- } else if(strcmp(argv[1],"setidx") == 0){
- return setIDX(pCon,pSics,self,argc,argv);
} else if(strcmp(argv[1],"settarget") == 0){
return setTarget(pCon,pSics,self,argc,argv);
} else if(strcmp(argv[1],"update") == 0){
return tasUpdate(pCon,self);
} else if(strcmp(argv[1],"del") == 0){
return deleteReflection(pCon,pSics,self,argc,argv);
+ } else if(strcmp(argv[1],"r1") == 0){
+ return readReflection(pCon,pSics,&self->r1,argc,argv);
+ } else if(strcmp(argv[1],"r2") == 0){
+ return readReflection(pCon,pSics,&self->r2,argc,argv);
} else if(strcmp(argv[1],"const") == 0){
if(argc > 2){
strtolower(argv[2]);
diff --git a/tasub.h b/tasub.h
index b703e863..f713db56 100644
--- a/tasub.h
+++ b/tasub.h
@@ -27,7 +27,8 @@
int mustRecalculate;
int mustDrive;
pMotor motors[12];
- int r1, r2;
+ tasReflection r1, r2;
+ int ubValid;
}tasUB, *ptasUB;
diff --git a/tasublib.c b/tasublib.c
index d311fb35..20efc6f0 100644
--- a/tasublib.c
+++ b/tasublib.c
@@ -18,6 +18,8 @@
#define PI 3.141592653589793
#define ECONST 2.072
#define DEGREE_RAD (PI/180.0) /* Radians per degree */
+#define VERT 0
+#define HOR 1
/*============== monochromator/analyzer stuff =========================*/
double energyToK(double energy){
double K;
@@ -33,8 +35,14 @@ double KtoEnergy(double k){
return energy;
}
/*-------------------------------------------------------------------*/
-static double calcCurvature(double B1, double B2, double theta){
- return B1 + B2/Sind(ABS(theta));
+static double calcCurvature(double B1, double B2, double theta,
+ int ori){
+ assert(ori == VERT || ori == HOR);
+ if(ori == VERT){
+ return B1 + B2/Sind(ABS(theta));
+ } else {
+ return B1 + B2*Sind(ABS(theta));
+ }
}
/*--------------------------------------------------------------------*/
int maCalcTwoTheta(maCrystal data, double k, double *two_theta){
@@ -51,11 +59,11 @@ int maCalcTwoTheta(maCrystal data, double k, double *two_theta){
}
/*--------------------------------------------------------------------*/
double maCalcVerticalCurvature(maCrystal data, double two_theta){
- return calcCurvature(data.VB1,data.VB2, two_theta/2.);
+ return calcCurvature(data.VB1,data.VB2, two_theta/2.,VERT);
}
/*-------------------------------------------------------------------*/
double maCalcHorizontalCurvature(maCrystal data, double two_theta){
- return calcCurvature(data.HB1,data.HB2, two_theta/2.);
+ return calcCurvature(data.HB1,data.HB2, two_theta/2.,HOR);
}
/*--------------------------------------------------------------------*/
double maCalcK(maCrystal data, double two_theta){
@@ -155,11 +163,22 @@ static MATRIX calcTasUVectorFromAngles(tasReflection r){
/*-------------------------------------------------------------------*/
MATRIX calcPlaneNormal(tasReflection r1, tasReflection r2){
MATRIX u1 = NULL, u2 = NULL, planeNormal = NULL;
+ int i;
u1 = calcTasUVectorFromAngles(r1);
u2 = calcTasUVectorFromAngles(r2);
if(u1 != NULL && u2 != NULL){
- return vectorCrossProduct(u1,u2);
+ planeNormal = vectorCrossProduct(u1,u2);
+ /*
+ The plane normal has to point to the stars and not to the earth
+ core in order for the algorithm to work.
+ */
+ if(planeNormal[2][0] < .0){
+ for(i = 0; i < 3; i++){
+ planeNormal[i][0] = -1.*planeNormal[i][0];
+ }
+ }
+ return planeNormal;
} else {
return NULL;
}
@@ -187,11 +206,15 @@ MATRIX calcTasUBFromTwoReflections(lattice cell, tasReflection r1,
h2 = tasReflectionToHC(r2.qe,B);
if(h1 == NULL || h2 == NULL){
*errorCode = UBNOMEMORY;
+ mat_free(B);
return NULL;
}
HT = matFromTwoVectors(h1,h2);
if(HT == NULL){
*errorCode = UBNOMEMORY;
+ mat_free(B);
+ mat_free(h1);
+ mat_free(h2);
return NULL;
}
@@ -202,39 +225,59 @@ MATRIX calcTasUBFromTwoReflections(lattice cell, tasReflection r1,
u2 = calcTasUVectorFromAngles(r2);
if(u1 == NULL || u2 == NULL){
*errorCode = UBNOMEMORY;
+ mat_free(B);
+ mat_free(h1);
+ mat_free(h2);
return NULL;
}
UT = matFromTwoVectors(u1,u2);
if(UT == NULL){
*errorCode = UBNOMEMORY;
+ mat_free(B);
+ mat_free(h1);
+ mat_free(h2);
+ mat_free(u1);
+ mat_free(u2);
+ mat_free(HT);
return NULL;
}
- /*
- debugging output
- printf("B-matrix\n");
- mat_dump(B);
- printf("HT-matrix\n");
- mat_dump(HT);
- printf("UT-matrix\n");
- mat_dump(UT);
- */
-
/*
UT = U * HT
*/
HTT = mat_tran(HT);
if(HTT == NULL){
*errorCode = UBNOMEMORY;
+ mat_free(B);
+ mat_free(h1);
+ mat_free(h2);
+ mat_free(u1);
+ mat_free(u2);
+ mat_free(HT);
return NULL;
}
U = mat_mul(UT,HTT);
if(U == NULL){
*errorCode = UBNOMEMORY;
+ mat_free(B);
+ mat_free(h1);
+ mat_free(h2);
+ mat_free(u1);
+ mat_free(u2);
+ mat_free(HT);
+ mat_free(HTT);
return NULL;
}
UB = mat_mul(U,B);
if(UB == NULL){
+ mat_free(B);
+ mat_free(h1);
+ mat_free(h2);
+ mat_free(u1);
+ mat_free(u2);
+ mat_free(HT);
+ mat_free(HTT);
+ mat_free(U);
*errorCode = UBNOMEMORY;
}
@@ -296,12 +339,14 @@ static MATRIX tasReflectionToQC(tasQEPosition r, MATRIX UB){
}
/*----------------------------------------------------------------------------*/
static MATRIX buildRMatrix(MATRIX UB, MATRIX planeNormal,
- tasQEPosition qe){
+ tasQEPosition qe, int *errorCode){
MATRIX U1V, U2V, TV, TVINV, M;
-
+
+ *errorCode = 1;
U1V = tasReflectionToQC(qe,UB);
if(U1V == NULL){
+ *errorCode = UBNOMEMORY;
return NULL;
}
normalizeVector(U1V);
@@ -309,6 +354,13 @@ static MATRIX buildRMatrix(MATRIX UB, MATRIX planeNormal,
U2V = vectorCrossProduct(planeNormal,U1V);
if(U2V == NULL){
killVector(U1V);
+ *errorCode = UBNOMEMORY;
+ return NULL;
+ }
+ if(vectorLength(U2V) < .0001){
+ *errorCode = BADUBORQ;
+ killVector(U1V);
+ killVector(U2V);
return NULL;
}
@@ -316,9 +368,14 @@ static MATRIX buildRMatrix(MATRIX UB, MATRIX planeNormal,
if(TV == NULL){
killVector(U1V);
killVector(U2V);
+ *errorCode = UBNOMEMORY;
return NULL;
}
+
TVINV = mat_inv(TV);
+ if(TVINV == NULL){
+ *errorCode = BADUBORQ;
+ }
killVector(U1V);
killVector(U2V);
@@ -329,30 +386,36 @@ static MATRIX buildRMatrix(MATRIX UB, MATRIX planeNormal,
int calcTasQAngles(MATRIX UB, MATRIX planeNormal, int ss, tasQEPosition qe,
ptasAngles angles){
MATRIX R, QC;
- double om, q, theta, cos2t, tmp, sq;
+ double om, q, theta, cos2t;
+ int errorCode = 1;
- R = buildRMatrix(UB, planeNormal, qe);
+ R = buildRMatrix(UB, planeNormal, qe, &errorCode);
if(R == NULL){
- return UBNOMEMORY;
+ return errorCode;
}
+
- sq = sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0]);
- if(ABS(sq) < .00001){
- return BADRMATRIX;
+ angles->sgl = Asind(-R[2][0]);
+ if(ABS(angles->sgl -90.) < .5){
+ return BADUBORQ;
}
- om = Acosd(R[0][0]/sq);
- om -= 180.;
- tmp = Asind(R[1][0]/sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0]));
+ /*
+ Now, this is slightly different then in the publication by M. Lumsden.
+ The reason is that the atan2 helps to determine the sign of om
+ whereas the sin, cos formula given by M. Lumsden yield ambiguous signs
+ especially for om.
+ sgu = atan(R[2][1],R[2][2]) where:
+ R[2][1] = cos(sgl)sin(sgu)
+ R[2][2] = cos(sgu)cos(sgl)
+ om = atan(R[1][0],R[0][0]) where:
+ R[1][0] = sin(om)cos(sgl)
+ R[0][0] = cos(om)cos(sgl)
+ The definitions of th R components are taken from M. Lumsden
+ R-matrix definition.
+ */
- tmp = Acosd(sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0]));
- angles->sgl = Asind(-R[2][0]);
-
- sq = sqrt(R[0][0]*R[0][0] + R[1][0]*R[1][0]);
- if(ABS(sq) < .00001){
- return BADRMATRIX;
- }
- angles->sgu = Asind(R[2][1]/sq);
- tmp = Acosd(R[2][2]/sqrt(R[0][0]*R[0][0]+R[1][0]*R[1][0]));
+ om = Atan2d(R[1][0],R[0][0]);
+ angles->sgu = Atan2d(R[2][1],R[2][2]);
QC = tasReflectionToQC(qe,UB);
if(QC == NULL){
@@ -370,6 +433,15 @@ int calcTasQAngles(MATRIX UB, MATRIX planeNormal, int ss, tasQEPosition qe,
theta = calcTheta(qe.ki, qe.kf,angles->sample_two_theta);
angles->a3 = om + theta;
+ /*
+ put a3 into -180, 180 properly. We cal always turn by 180 because the
+ scattering geometry is symmetric in this respect. It is like looking at
+ the scattering plane from the other side
+ */
+ angles->a3 -= 180.;
+ if(angles->a3 < -180.){
+ angles->a3 += 360.;
+ }
killVector(QC);
mat_free(R);
@@ -395,9 +467,10 @@ int calcTasQH(MATRIX UB, tasAngles angles, ptasQEPosition qe){
Thereby take into account the physicists magic fudge
2PI factor
*/
- q = sqrt(qe->ki*qe->ki + qe->kf*qe->kf - 2.*qe->ki*qe->kf*Cosd(angles.sample_two_theta));
- q /= 2. * PI;
+ q = sqrt(qe->ki*qe->ki + qe->kf*qe->kf -
+ 2.*qe->ki*qe->kf*Cosd(angles.sample_two_theta));
qe->qm = q;
+ q /= 2. * PI;
for(i = 0; i < 3; i++){
QV[i][0] *= q;
@@ -431,14 +504,14 @@ int calcAllTasAngles(ptasMachine machine, tasQEPosition qe,
return status;
}
- status = calcTasQAngles(machine->UB, machine->planeNormal,
- machine->ss_sample, qe,angles);
+ status = maCalcTwoTheta(machine->analyzer,qe.kf,&
+ angles->analyzer_two_theta);
if(status != 1){
return status;
}
- status = maCalcTwoTheta(machine->analyzer,qe.kf,&
- angles->analyzer_two_theta);
+ status = calcTasQAngles(machine->UB, machine->planeNormal,
+ machine->ss_sample, qe,angles);
if(status != 1){
return status;
}
@@ -498,7 +571,6 @@ int calcTasPowderPosition(ptasMachine machine, tasAngles angles,
qe->qm = sqrt(qe->ki*qe->ki + qe->kf*qe->kf -
2.*qe->ki*qe->kf*Cosd(angles.sample_two_theta));
-
return 1;
}
/*====================== Logic implementation =========================*/
@@ -582,6 +654,3 @@ double getTasPar(tasQEPosition qe, int tasVar){
assert(0);
}
}
-
-
-
diff --git a/tasublib.h b/tasublib.h
index 8a4ab20c..4fad553a 100644
--- a/tasublib.h
+++ b/tasublib.h
@@ -17,6 +17,7 @@
#define UBNOMEMORY -702
#define TRIANGLENOTCLOSED -703
#define BADRMATRIX -704
+#define BADUBORQ -705
/*========================== defines for tasMode ====================*/
#define KICONST 1
#define KFCONST 2
diff --git a/trigd.c b/trigd.c
index b3cb8953..807087ba 100644
--- a/trigd.c
+++ b/trigd.c
@@ -53,6 +53,16 @@ extern double Atand (double x)
return (data);
}
/*******************************************************************************
+* Atan of angle in degrees.
+*******************************************************************************/
+extern double Atan2d (double x, double y)
+{
+ double data;
+
+ data = (atan2(x,y)/DEGREE_RAD);
+ return (data);
+}
+/*******************************************************************************
* Atan2 of angle in degrees.
*******************************************************************************/
extern double Atand2 (double x)
diff --git a/trigd.h b/trigd.h
index bf3c6c47..9aa7697f 100644
--- a/trigd.h
+++ b/trigd.h
@@ -14,4 +14,5 @@
double Atand2 (double x);
double Acosd (double x);
double Asind (double x);
+ double Atan2d(double x, double y);
#endif