PSI update

r1464 | ffr | 2007-02-12 12:20:21 +1100 (Mon, 12 Feb 2007) | 2 lines
This commit is contained in:
Ferdi Franceschini
2007-02-12 12:20:21 +11:00
committed by Douglas Clowes
parent 634f2023b1
commit 3168325921
157 changed files with 29053 additions and 910 deletions

View File

@ -1,5 +1,5 @@
#line 462 "histogram.w" #line 465 "histogram.w"
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
H I S T D R I V H I S T D R I V
@ -58,6 +58,9 @@
SConnection *pCon); SConnection *pCon);
float (*GetTime)(pHistDriver self, float (*GetTime)(pHistDriver self,
SConnection *pCon); SConnection *pCon);
HistInt *(*SubSample)(pHistDriver self,
SConnection *pCon,int bank,
char *command);
int (*Preset)(pHistDriver self, int (*Preset)(pHistDriver self,
SConnection *pCon, SConnection *pCon,
HistInt iVal); HistInt iVal);
@ -69,17 +72,17 @@
void *pPriv; void *pPriv;
} HistDriver; } HistDriver;
#line 474 "histogram.w" #line 477 "histogram.w"
#line 229 "histogram.w" #line 232 "histogram.w"
pHistDriver CreateHistDriver(pStringDict pDict); pHistDriver CreateHistDriver(pStringDict pDict);
void DeleteHistDriver(pHistDriver self); void DeleteHistDriver(pHistDriver self);
int HistDriverConfig(pHistDriver self, pStringDict pOpt, int HistDriverConfig(pHistDriver self, pStringDict pOpt,
SConnection *pCon); SConnection *pCon);
#line 475 "histogram.w" #line 478 "histogram.w"
#endif #endif

View File

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

View File

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

View File

@ -41,7 +41,7 @@
Mark Koennecke, August 2001, modified SicsWriteStatus to write motor Mark Koennecke, August 2001, modified SicsWriteStatus to write motor
positions on demand. positions on demand.
Made ListObjects moe intelligent: list objects according to interface etc. Made ListObjects more intelligent: list objects according to interface etc.
Mark Koennecke, December 2003 Mark Koennecke, December 2003
Extended 'dir' command (function ListObjects) to list via typename from Extended 'dir' command (function ListObjects) to list via typename from
@ -50,6 +50,8 @@
Modified printXXX functions to fix duplicate write of last buffer line. Modified printXXX functions to fix duplicate write of last buffer line.
Paul Hathaway, May 2004 Paul Hathaway, May 2004
Added FindAlias function, Mark Koennecke, January 2007
---------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -67,6 +69,7 @@
#include "motor.h" #include "motor.h"
#include "obdes.h" #include "obdes.h"
#include "lld.h" #include "lld.h"
#include "dynstring.h"
/* M.Z. */ /* M.Z. */
#include "definealias.h" #include "definealias.h"
@ -134,6 +137,7 @@ static void freeList(int listID);
SICSLogWrite(pBueffel,eInternal); SICSLogWrite(pBueffel,eInternal);
return 0; return 0;
} }
memset(pNew,0,sizeof(CommandList));
/* if no data given, initialise with Dummy struct */ /* if no data given, initialise with Dummy struct */
if(!pData) if(!pData)
@ -431,7 +435,7 @@ extern char *SkipSpace(char *pPtr);
} }
if(fVal > -990.) if(fVal > -990.)
{ {
fprintf(fd,"run %s %f\n",pCurrent->pName, fVal); fprintf(fd,"drive %s %f\n",pCurrent->pName, fVal);
} }
} }
} }
@ -1041,3 +1045,64 @@ static void freeList(int listID)
pCurrent = pNext; pCurrent = pNext;
} }
} }
/*---------------------------------------------------------------------*/
char *FindAliases(SicsInterp *pSics, char *name)
{
pDynString result = NULL;
CommandList *pOri = NULL, *pCom = NULL;
char *pTrans = NULL, *charResult = NULL;
int first;
pOri = FindCommand(pSics, name);
if(pOri == NULL)
{
return NULL;
}
if(pOri->pData == NULL)
{
return NULL;
}
result = CreateDynString(64,64);
if(result == NULL)
{
return NULL;
}
/* try first to locate Markus style aliases */
pTrans = TranslateAlias(&pSics->AList,name);
if(strcmp(pTrans,name) != 0)
{
DynStringCopy(result,pTrans);
charResult = strdup(GetCharArray(result));
DeleteDynString(result);
return charResult;
}
/*
* locate SicsAlias style aliases by comparing the original
* data pointer with the data pointers of other commands
*/
first = 1;
pCom = pSics->pCList;
while(pCom != NULL)
{
if(pCom != pOri && pCom->pData == pOri->pData)
{
if(first)
{
DynStringCopy(result,pCom->pName);
first = 0;
}
else
{
DynStringConcat(result,",");
DynStringConcat(result,pCom->pName);
}
}
pCom = pCom->pNext;
}
charResult = strdup(GetCharArray(result));
DeleteDynString(result);
return charResult;
}

View File

@ -51,7 +51,8 @@ typedef enum {
eEvent, eEvent,
eWarning, eWarning,
eError, eError,
eHdb eHdbValue,
eHdbEvent
} OutCode; } OutCode;
#include "interrupt.h" #include "interrupt.h"

View File

@ -113,6 +113,7 @@ static long ColliderSetValue(void *pData, SConnection *pCon, float fTarget){
iRet = Tcl_Eval(pServ->pSics->pTcl,Tcl_DStringValue(&command)); iRet = Tcl_Eval(pServ->pSics->pTcl,Tcl_DStringValue(&command));
if(iRet != TCL_OK){ if(iRet != TCL_OK){
SCWrite(pCon,"ERROR: Movement not possible or bad collider script",eError); SCWrite(pCon,"ERROR: Movement not possible or bad collider script",eError);
SCWrite(pCon,Tcl_DStringValue(&command),eError);
/* /*
SCWrite(pCon,pServ->pSics->pTcl->result,eError); SCWrite(pCon,pServ->pSics->pTcl->result,eError);
*/ */

View File

@ -39,6 +39,8 @@
fields. fields.
Mark Koennecke, December 2004 Mark Koennecke, December 2004
Aded buffering support, Mark Koennecke, July 2006
Copyright: see copyright.h Copyright: see copyright.h
-----------------------------------------------------------------------------*/ -----------------------------------------------------------------------------*/
#include "fortify.h" #include "fortify.h"
@ -92,6 +94,8 @@ extern pServer pServ;
static int iName = 0; static int iName = 0;
static SConnection *freeConnections = NULL; static SConnection *freeConnections = NULL;
static long lastIdent = 0; static long lastIdent = 0;
/*------------- sending connection (prevent double write when listening) ----*/
static SConnection *sendingConnection = NULL;
/*===========================================================================*/ /*===========================================================================*/
static char *ConName(long ident) { static char *ConName(long ident) {
static char name[32]; static char name[32];
@ -457,6 +461,11 @@ extern pServer pServ;
DeleteCommandStack(pVictim->pStack); DeleteCommandStack(pVictim->pStack);
} }
/* remove possible buffers */
if(pVictim->data != NULL)
{
DeleteDynString(pVictim->data);
}
pVictim->lMagic=0; /* make a write to a freed connection harmless */ pVictim->lMagic=0; /* make a write to a freed connection harmless */
/* finally free pVictim*/ /* finally free pVictim*/
@ -692,11 +701,22 @@ static void writeToLogFiles(SConnection *self, char *buffer)
SICSLogWrite(buffer,iOut); SICSLogWrite(buffer,iOut);
/* write to commandlog if user or manager privilege */ /* write to commandlog if user or manager privilege */
if(SCGetRights(self) <= usUser && self->iMacro != 1) if(SCGetRights(self) <= usUser)
{
if(self->iMacro != 1)
{ {
sprintf(pBueffel,"To sock %d :",iRet); sprintf(pBueffel,"To sock %d :",iRet);
WriteToCommandLog(pBueffel,buffer); WriteToCommandLog(pBueffel,buffer);
} }
else
{
if(iOut == eError || iOut == eWarning)
{
sprintf(pBueffel,"To sock %d :",iRet);
WriteToCommandLog(pBueffel,buffer);
}
}
}
/* put it into the interpreter if present */ /* put it into the interpreter if present */
if(SCinMacro(self)) if(SCinMacro(self))
@ -754,7 +774,9 @@ static void writeToLogFiles(SConnection *self, char *buffer)
if(SCGetRights(self) <= usUser && self->iMacro != 1) if(SCGetRights(self) <= usUser && self->iMacro != 1)
{ {
sprintf(pBueffel,"To sock %d :",iRet); sprintf(pBueffel,"To sock %d :",iRet);
sendingConnection = self;
WriteToCommandLog(pBueffel,buffer); WriteToCommandLog(pBueffel,buffer);
sendingConnection = NULL;
} }
/* /*
@ -809,6 +831,52 @@ static void writeToLogFiles(SConnection *self, char *buffer)
free(bufPtr); free(bufPtr);
return 1; return 1;
} }
/*-------------------------------------------------------------------------*/
static int SCBufferWrite(SConnection *self, char *buffer, int iOut)
{
if(!VerifyConnection(self))
{
return 0;
}
assert(self->data != NULL);
DynStringConcat(self->data,buffer);
if(strchr(buffer,'\n') == NULL){
DynStringConcat(self->data,"\n");
}
return 1;
}
/*-------------------------------------------------------------------------*/
int SCStartBuffering(SConnection *pCon)
{
if(!VerifyConnection(pCon))
{
return 0;
}
if(pCon->data != NULL)
{
DeleteDynString(pCon->data);
}
pCon->data = CreateDynString(128,128);
if(pCon->data == NULL)
{
return 0;
}
pCon->oldWriteFunc = pCon->write;
pCon->write = SCBufferWrite;
return 1;
}
/*-------------------------------------------------------------------------*/
pDynString SCEndBuffering(SConnection *pCon)
{
if(!VerifyConnection(pCon))
{
return 0;
}
assert(pCon->oldWriteFunc != NULL);
pCon->write = pCon->oldWriteFunc;
pCon->oldWriteFunc = NULL;
return pCon->data;
}
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
int SCOnlySockWrite(SConnection *self, char *buffer, int iOut) int SCOnlySockWrite(SConnection *self, char *buffer, int iOut)
{ {
@ -1378,7 +1446,16 @@ static void writeToLogFiles(SConnection *self, char *buffer)
{ {
strcat(pBueffel,"CONT or CRON>> "); strcat(pBueffel,"CONT or CRON>> ");
} }
/*
* This is a fix to suppress cron messages in the success
* case
*/
if(SCGetWriteFunc(self) != SCNotWrite)
{
sendingConnection = self;
WriteToCommandLog(pBueffel,pCommand); WriteToCommandLog(pBueffel,pCommand);
sendingConnection = NULL;
}
} }
/* invoke */ /* invoke */
@ -1900,8 +1977,8 @@ static void writeToLogFiles(SConnection *self, char *buffer)
SCSetRights(self,iRet); SCSetRights(self,iRet);
pHost[0] = '\0'; pHost[0] = '\0';
NETInfo(self->pSock,pHost,131); NETInfo(self->pSock,pHost,131);
sprintf(pBueffel,"Accepted connection on socket %d from %s", sprintf(pBueffel,"Accepted connection %s on socket %d from %s",
self->pSock->sockid, pHost); ConName(self->ident), self->pSock->sockid, pHost);
SICSLogWrite(pBueffel,eInternal); SICSLogWrite(pBueffel,eInternal);
WriteToCommandLog("SYS >", pBueffel); WriteToCommandLog("SYS >", pBueffel);
free(pPtr); free(pPtr);
@ -1965,7 +2042,7 @@ static void writeToLogFiles(SConnection *self, char *buffer)
else if(iSignal == COMLOG && self->listening == 1) else if(iSignal == COMLOG && self->listening == 1)
{ {
pPtr = (char *)pSigData; pPtr = (char *)pSigData;
if(pPtr != NULL) if(pPtr != NULL && self != sendingConnection)
{ {
doSockWrite(self,pPtr); doSockWrite(self,pPtr);
} }

View File

@ -24,6 +24,7 @@
#include "network.h" #include "network.h"
#include "obdes.h" #include "obdes.h"
#include "commandcontext.h" #include "commandcontext.h"
#include "dynstring.h"
#define MAXLOGFILES 10 #define MAXLOGFILES 10
@ -60,6 +61,12 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
int parameterChange; int parameterChange;
int sicsError; int sicsError;
/*
* for I/O Buffering
*/
pDynString data;
writeFunc oldWriteFunc;
/* /*
stuff supporting the sycamore protocol and a stuff supporting the sycamore protocol and a
command context command context
@ -116,6 +123,9 @@ typedef int (*writeFunc)(struct __SConnection *pCon,
int SCNotWrite(SConnection *self, char *buffer, int iOut); int SCNotWrite(SConnection *self, char *buffer, int iOut);
int SCNormalWrite(SConnection *self, char *buffer, int iOut); int SCNormalWrite(SConnection *self, char *buffer, int iOut);
int SCWriteWithOutcode(SConnection *self, char *buffer, int iOut); int SCWriteWithOutcode(SConnection *self, char *buffer, int iOut);
/*********************** I/O Buffering ***********************************/
int SCStartBuffering(SConnection *pCon);
pDynString SCEndBuffering(SConnection *pCon);
/************************* CallBack *********************************** */ /************************* CallBack *********************************** */
int SCRegister(SConnection *pCon, SicsInterp *pSics, int SCRegister(SConnection *pCon, SicsInterp *pSics,
void *pInter, long lID); void *pInter, long lID);

View File

@ -88,4 +88,10 @@
* file: mcstascounter.c * file: mcstascounter.c
*/ */
pCounterDriver NewMcStasCounter(char *name); pCounterDriver NewMcStasCounter(char *name);
/*
* for regression testing
* file: regresscter.c
*/
pCounterDriver NewRegressCounter(char *name);
#endif #endif

View File

@ -314,7 +314,7 @@
for(i = 0; i < 3; i++) for(i = 0; i < 3; i++)
{ {
iRet = self->pDriv->ReadValues(self->pDriv); iRet = self->pDriv->ReadValues(self->pDriv);
if(iRet) if(iRet == OKOK)
{ {
self->isUpToDate = 1; self->isUpToDate = 1;
return OKOK; return OKOK;
@ -529,6 +529,13 @@
} }
} }
/*
* test for regression testing counter
*/
if(strcmp(argv[2],"regress") == 0){
pDriv = NewRegressCounter(argv[1]);
}
/* /*
* test for McStas simulation counter driver * test for McStas simulation counter driver
*/ */
@ -907,6 +914,7 @@
SCSendOK(pCon); SCSendOK(pCon);
return 1; return 1;
case 11: /* status */ case 11: /* status */
self->pCountInt->TransferData(self,pCon);
if(GetCounterMode(self) == ePreset) if(GetCounterMode(self) == ePreset)
{ {
sprintf(pBueffel,"%s.CountStatus = %d %d Beam: %ld E6", sprintf(pBueffel,"%s.CountStatus = %d %d Beam: %ld E6",

View File

@ -70,18 +70,23 @@ static FILE *devLog = NULL;
int openDevexecLog(){ int openDevexecLog(){
char *fileName = NULL; char *fileName = NULL;
char fileBuffer[1024]; char fileBuffer[1024];
time_t iDate;
struct tm *psTime;
if(devLog == NULL){ if(devLog == NULL){
fileName = IFindOption(pSICSOptions,"devexeclog"); fileName = IFindOption(pSICSOptions,"devexeclog");
if(fileName != NULL){ if(fileName != NULL){
strcpy(fileBuffer,fileName); strcpy(fileBuffer,fileName);
} else { } else {
iDate = time(NULL);
psTime = localtime(&iDate);
fileBuffer[0] = '\0'; fileBuffer[0] = '\0';
fileName = getenv("HOME"); fileName = getenv("HOME");
if(fileName != NULL){ if(fileName != NULL){
strcpy(fileBuffer,fileName); snprintf(fileBuffer,1023,"%s/log/devexec%4.4d.log",
fileName, psTime->tm_year + 1900);
} }
strcat(fileBuffer,"/log/devexec.log");
} }
devLog = fopen(fileBuffer,"a+"); devLog = fopen(fileBuffer,"a+");
} }
@ -168,6 +173,20 @@ typedef struct {
} ExeList; } ExeList;
static pExeList pExecutor = NULL; static pExeList pExecutor = NULL;
/*--------------------------------------------------------------------------*/
static void *DevexecInterface(void *pData, int iInter)
{
pExeList self = NULL;
self = (pExeList)pData;
assert(self);
if(iInter == CALLBACKINTERFACE)
{
return self->pCall;
}
return NULL;
}
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
pExeList CreateExeList(pTaskMan pTask) pExeList CreateExeList(pTaskMan pTask)
{ {
@ -200,8 +219,10 @@ typedef struct {
pRes->lTask = -1; pRes->lTask = -1;
pRes->iLock = 0; pRes->iLock = 0;
pRes->drivePrint = 0; pRes->drivePrint = 0;
pRes->paused = 0;
pRes->pCall = CreateCallBackInterface(); pRes->pCall = CreateCallBackInterface();
pRes->lastRun = time(NULL); pRes->lastRun = time(NULL);
pRes->pDes->GetInterface = DevexecInterface;
return pRes; return pRes;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
@ -508,7 +529,7 @@ typedef struct {
ExeInterest(self, pDev, "finished"); ExeInterest(self, pDev, "finished");
DeleteDevEntry(pDev); DeleteDevEntry(pDev);
LLDnodeDelete(self->iList); LLDnodeDelete(self->iList);
SCWrite(pCon, "Finished", eFinish); SCWrite(pCon, "", eFinish);
iRet = LLDnodePtr2Prev(self->iList); iRet = LLDnodePtr2Prev(self->iList);
if(SCGetInterrupt(self->pOwner) != eContinue) if(SCGetInterrupt(self->pOwner) != eContinue)
{ {
@ -667,7 +688,6 @@ static int errorDevice(pCheckContext pCheck){
ExeInterest(pCheck->self, pCheck->pDev, "finished with problem"); ExeInterest(pCheck->self, pCheck->pDev, "finished with problem");
DevexecLog("STOP",pCheck->pDev->name); DevexecLog("STOP",pCheck->pDev->name);
DeleteDevEntry(pCheck->pDev);
LLDnodeDelete(pCheck->self->iList); LLDnodeDelete(pCheck->self->iList);
status = LLDnodePtr2Prev(pCheck->self->iList); status = LLDnodePtr2Prev(pCheck->self->iList);
SCWrite(pCheck->self->pOwner, "", eFinish); SCWrite(pCheck->self->pOwner, "", eFinish);
@ -675,7 +695,9 @@ static int errorDevice(pCheckContext pCheck){
if(pCheck->pDrivInt != NULL) { if(pCheck->pDrivInt != NULL) {
pCheck->pDrivInt->iErrorCount++; pCheck->pDrivInt->iErrorCount++;
} }
return checkInterrupt(pCheck,status); status = checkInterrupt(pCheck,status);
DeleteDevEntry(pCheck->pDev);
return status;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static int testFinish(pExeList self){ static int testFinish(pExeList self){
@ -1143,7 +1165,7 @@ static int testFinish(pExeList self){
SCPopContext(pCon); SCPopContext(pCon);
return 1; return 1;
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
int ListExe(SConnection *pCon, SicsInterp *pSics, void *pData, int ListExe(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]) int argc, char *argv[])
{ {

View File

@ -118,6 +118,8 @@
#line 259 "devexec.w" #line 259 "devexec.w"
/*-------------------------- Commands ------------------------------------*/ /*-------------------------- Commands ------------------------------------*/
int DevexecAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int StopCommand(SConnection *pCon, SicsInterp *pSics, void *pData, int StopCommand(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
/* /*
@ -152,11 +154,7 @@
/* /*
continues execution continues execution
*/ */
int DevexecAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
/*
* various commands
*/
/*--------------------------- Locking ---------------------------------*/ /*--------------------------- Locking ---------------------------------*/
#line 183 "devexec.w" #line 183 "devexec.w"
@ -165,7 +163,7 @@
void UnlockDeviceExecutor(pExeList self); void UnlockDeviceExecutor(pExeList self);
#line 297 "devexec.w" #line 299 "devexec.w"
/* -------------------------- Executor management -------------------------*/ /* -------------------------- Executor management -------------------------*/

View File

@ -312,6 +312,8 @@ to the global SICS device executor.
\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\ \mbox{}\verb@/*-------------------------------------------------------------------------*/@\\
\mbox{}\verb@@$\langle$devstop {\footnotesize ?}$\rangle$\verb@@\\ \mbox{}\verb@@$\langle$devstop {\footnotesize ?}$\rangle$\verb@@\\
\mbox{}\verb@/*-------------------------- Commands ------------------------------------*/@\\ \mbox{}\verb@/*-------------------------- Commands ------------------------------------*/@\\
\mbox{}\verb@ int DevexecAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ int StopCommand(SConnection *pCon, SicsInterp *pSics, void *pData,@\\ \mbox{}\verb@ int StopCommand(SConnection *pCon, SicsInterp *pSics, void *pData,@\\
\mbox{}\verb@ int argc, char *argv[]);@\\ \mbox{}\verb@ int argc, char *argv[]);@\\
\mbox{}\verb@ /*@\\ \mbox{}\verb@ /*@\\

View File

@ -258,6 +258,8 @@ to the global SICS device executor.
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
@<devstop@> @<devstop@>
/*-------------------------- Commands ------------------------------------*/ /*-------------------------- Commands ------------------------------------*/
int DevexecAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]);
int StopCommand(SConnection *pCon, SicsInterp *pSics, void *pData, int StopCommand(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
/* /*

View File

@ -104,7 +104,7 @@ the dictionary file:
would denote the normal counting tube at a scanning type of would denote the normal counting tube at a scanning type of
experiment. experiment.
</dl> </dl>
<dt>nxscript puthm hmAlias hmName ?start? ?length? <dt>nxscript puthm hmAlias hmName ?start? ?length? ?bank?
<dd>Writes data from the histogram memory hmName to a NeXus file using <dd>Writes data from the histogram memory hmName to a NeXus file using
the alias hmAlias. Nxscript automatically updates the dim0, dim1, ..., timedim the alias hmAlias. Nxscript automatically updates the dim0, dim1, ..., timedim
dictionary variables. Thus these can be used to define the dimensions in the dictionary variables. Thus these can be used to define the dimensions in the
@ -116,7 +116,9 @@ subset writing, the dimensions have to be specified in the definition
string belonging to the alias. Nxscript sets a variable timedim in the string belonging to the alias. Nxscript sets a variable timedim in the
dictionary though which contains the length of a time binning if dictionary though which contains the length of a time binning if
appropriate. This is a special feauture for writing extra detectors at appropriate. This is a special feauture for writing extra detectors at
SANS and AMOR. SANS and AMOR. Optionally, together with start and length, a bank number can
be given. This is a feauture to support the rare case of having multiple banks
in one histogram memory. If not give bank defaults to 0.
<dt>nxscript puttimebinning aliasName hmName <dt>nxscript puttimebinning aliasName hmName
<dd>Writes the time binning at histogram memory hmName to file using <dd>Writes the time binning at histogram memory hmName to file using
the alias aliasName. The length of the time binning data is the alias aliasName. The length of the time binning data is
@ -125,11 +127,19 @@ automatically appended to the definition string for the alias.
<dd>Writes the Tcl array arrayName to file using the aliasName. The <dd>Writes the Tcl array arrayName to file using the aliasName. The
definiton string belonging to aliasName does not need to contain a definiton string belonging to aliasName does not need to contain a
-dim argument as this is set by this routine. The parameter length is -dim argument as this is set by this routine. The parameter length is
the length of the array. Only rank 1 arrays are supported. the length of the array. Only rank 1 arrays are supported. The array is
considered a float array.
<dt>nxscript putintarray aliasName arrayName length
<dd>The same as above, but the data is considered integer.
<dt>nxsript putglobal attName bla bla bla <dt>nxsript putglobal attName bla bla bla
<dd>This writes an global attribute attName. Everything after attName <dd>This writes an global attribute attName. Everything after attName
is concatenated to a string which then respresents the value of the is concatenated to a string which then respresents the value of the
attribute. attribute.
<dt>nxscript putsicsdata alias dataname
<dd>Writes the sicsdata array dataname to alias.
<dt>nxscript putattribute alias name value
<dd>Add another text attribute to alias. The name of the attribute is name, the
value value.
<dt>nxscript makelink targetAlias victimAlias <dt>nxscript makelink targetAlias victimAlias
<dd>This creates a symbolic link for victimAlias in the group <dd>This creates a symbolic link for victimAlias in the group
designated by targetAlias. designated by targetAlias.

View File

@ -65,6 +65,9 @@ file.
<dt>updateintervall <dt>updateintervall
<dd>The time intervall in seconds between updates. The defualt is <dd>The time intervall in seconds between updates. The defualt is
1200, eg. 20 minutes. 1200, eg. 20 minutes.
<dt>onoff
<dd>can be 1 or 0. Switches automatic updates on or off. It might be usefule for
scans to switch this off.
</dl> </dl>
</p> </p>
</BODY> </BODY>

View File

@ -21,6 +21,37 @@ The TAS requires the following initializations in its instrument file:
<dt>MakeTasUB tasub <dt>MakeTasUB tasub
<dd>Installs the TAS crystallographic calculation module into SICS. It will <dd>Installs the TAS crystallographic calculation module into SICS. It will
have the name tasub (recommended). have the name tasub (recommended).
<dt>MakeTasUB tasub a1 a2 mcv mch a3 a4 sgu sgl a5 a6 acv ach
<dd>Installs the TAS crystallographic calculation module into SICS. It will
have the name tasub (recommended). This versions allows to specifiy motor names for functions. If there is no motor for
a function it can be replaced with a placeholder in the parameter list, like dummy. This is only allowed for the
curvature motors. The motor functions:
<dl>
<dt>a1
<dd>monochormator rotation
<dt>a2
<dd>monochromator two theta
<dt>mcv
<dd>monochromator vertical curvature
<dt>mch
<dd>monochromator horizontal curvature
<dt>a3
<dd> sample rotation
<dt>a4
<dd>sample tow theta
<dt>sgu
<dd>sample tilt
<dt>sgl
<dd>second sample tilt
<dt>a5
<dd>analyzer rotation
<dt>a6
<dd>analyzer two theta
<dt>acv
<dd>analyzer vertical curvature
<dt>ach
<dd>analyzer horizontal curvature
</dl>
<dt>MakeTasScan iscan tasub <dt>MakeTasScan iscan tasub
<dd>Installs the module with the TAS specific scan functions into SICS. The <dd>Installs the module with the TAS specific scan functions into SICS. The
TAS implements its own data format resembling the ILL TAS data format. TAS implements its own data format resembling the ILL TAS data format.

View File

@ -35,6 +35,11 @@ started. In order to make this work a ServerOption with the name logstartfile
must exist in the instrument configuration file. The value of this option must exist in the instrument configuration file. The value of this option
must be the full path name of the file to execute. must be the full path name of the file to execute.
</P> </P>
<p>
<b>Note:</b> with the command <it>config listen 1</it> you can have the output
to the command log printed into your client, too. With <it>config listen 0</it> you can switch this off again. This is useful for listening into a running
instrument.
</p>
</BODY> </BODY>
</HTML> </HTML>

View File

@ -45,6 +45,13 @@ named buffer within the stack of nested buffers.
<dt>Clears the queue of batch buffers <dt>Clears the queue of batch buffers
<dt>exe queue <dt>exe queue
<dd>Prints the content of the batch buffer queue. <dd>Prints the content of the batch buffer queue.
<dt>exe fullpath filename
<dd>Prints the full path name for filename if the file can be located
somewhere in exe paths. Else an error is printed. The purpose is to use
exe file management facilties in scripts.
<dt>exe makepath filename
<dd>Prints the full path name for filename in the first direcory of batch path.
This is a tool to have scripts open files in the proper user directory.
<dt>exe run <dt>exe run
<dd>Starts executing the batch buffers in the queue. <dd>Starts executing the batch buffers in the queue.
<dt>exe print buffername <dt>exe print buffername
@ -58,7 +65,12 @@ most useful for SICS clients watching the progress of the experiment.
<dt>exe append some text <dt>exe append some text
<dd> Appends a line with everything after append to the upload buffer <dd> Appends a line with everything after append to the upload buffer
<dt>exe save filename <dt>exe save filename
<dd>saves the recently uploaded buffer under filename on the SICS server. <dd>saves the recently uploaded buffer under filename on the SICS server. Does not overwrite
existing files.
<dt>exe forcesave filename
<dd>saves the recently uploaded buffer under filename on the SICS server. Overwrites existing file.
<dt>exe clearupload
<dd>clears any pending upload operations.
</dl> </dl>
</P> </P>
</BODY> </BODY>

View File

@ -29,6 +29,18 @@ maximum number of cycles was reached. This routine requires that the
instrument is currently placed somewhere on the peak and not miles away. instrument is currently placed somewhere on the peak and not miles away.
</P> </P>
<p> <p>
The peak optimiser supports another optimisation algorithm which is faster but
may not be as accurate. This is hill climbing:
<pre>
while errors gt precision and cycles lt maxcycles
for all variables
find the direction into which the intensity rises
step into this direction until the intensity drops
end for
end while
</pre>
</p>
<p>
The Peak Optimiser is implemented as an object with the name opti. It The Peak Optimiser is implemented as an object with the name opti. It
understand the following commands: understand the following commands:
<DL> <DL>
@ -43,7 +55,10 @@ and number of steps parameters should cover the whole peak. However, the
Optimiser will extend the scan is the specified range is not sufficient. Optimiser will extend the scan is the specified range is not sufficient.
<DT>opti run <DT>opti run
<DD>Starts the optimiser. It will then optimise the peak. This may take some <DD>Starts the optimiser. It will then optimise the peak. This may take some
time. time as it uses a time consuming scan based algorithm.
<DT>opti climb
<DD>Starts the optimiser in hill climbing mode. Hill climbing is faster but may
not be as accurate as a scan based optimization.
</DL> </DL>
The behaviour of the optimiser can be configured by modifying some The behaviour of the optimiser can be configured by modifying some
parameters. The synatx is easy: <b>opti parameter</b> prints the value of the parameters. The synatx is easy: <b>opti parameter</b> prints the value of the
@ -72,5 +87,12 @@ status of the countmode parameter this is either a preset time or a preset
monitor. monitor.
</DL> </DL>
</p> </p>
<p>
It is the users reponsability to provide meaningful step widths. Usually this is
dependent on the instrument resolution and thus fairly constant. Also these
optimisation algorithms will fail if the instrument is not positioned at the
flank of a peak. Probaly the best will be to do several cycles of hill
climbing first, followed by one cycle of scan optimisation for extra accuracy.
</p>
</BODY> </BODY>
</HTML> </HTML>

5284
doc/user/sansdocbook.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -81,6 +81,12 @@ In order to calculate a UB matrix a list of reflections must be maintained. This
<dd>Add a new reflection to the list. Besides the indices all angles are given: <dd>Add a new reflection to the list. Besides the indices all angles are given:
a3, the sample rotation, a4, sample two theta, sgu, upper tilt cradle, sgl, lower tilt a3, the sample rotation, a4, sample two theta, sgu, upper tilt cradle, sgl, lower tilt
cradle and incoming energey ei and outgoing energy ef. cradle and incoming energey ei and outgoing energy ef.
<dt>tasub addauxref qh qk ql
<dd>Adds an auxiliary reflection with indices qh, qk, ql to the list. A4 is
calculated from cell constants. A3 is either left alone or is calculated to
have the correct angular difference to a previous reflection. This is a help
for setting up the instrument or running powder mode. When a UB has been
generated from auxiliary reflections, a3, sgu and sgl angles will be incorrect.
</dl> </dl>
</p> </p>
<h3>Calculations</h3> <h3>Calculations</h3>

View File

@ -971,12 +971,15 @@ static void ErrReport(pEVControl self)
{ {
ObPar *pPar = NULL; ObPar *pPar = NULL;
char pBueffel[512]; char pBueffel[512];
int iRet; int iRet, savedStatus;
assert(self); assert(self);
assert(pCon); assert(pCon);
savedStatus = GetStatus(); /* fool status check in ObParSet (avoid "Cannot change parameter while running" message */
SetStatus(eBatch);
iRet = ObParSet(self->pParam,self->pName,name,fVal,pCon); iRet = ObParSet(self->pParam,self->pName,name,fVal,pCon);
SetStatus(savedStatus);
if(!iRet) if(!iRet)
{ {
return iRet; return iRet;
@ -1102,8 +1105,11 @@ static void ErrReport(pEVControl self)
iRet = EVCGetPos(self,pCon,&fPos); iRet = EVCGetPos(self,pCon,&fPos);
if(iRet) if(iRet)
{ {
/*
sprintf(pBueffel,"%s.%s = %g",self->pName,"CurrentValue", fPos); sprintf(pBueffel,"%s.%s = %g",self->pName,"CurrentValue", fPos);
SCWrite(pCon,pBueffel,eValue); SCWrite(pCon,pBueffel,eValue);
*/
SCPrintf(pCon, eValue, "%s = %g", self->pName, fPos);
return 1; return 1;
} }
return 0; return 0;

View File

@ -64,6 +64,11 @@
"BATCHAREA", "BATCHAREA",
"BATCHEND", "BATCHEND",
"DRIVSTAT", "DRIVSTAT",
"STATUS",
"POSITION",
"HDBVAL",
"STATESTART",
"STATEEND",
NULL NULL
}; };

20
event.h
View File

@ -1,5 +1,5 @@
#line 89 "event.w" #line 103 "event.w"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
E V E N T E V E N T
@ -14,15 +14,15 @@
#ifndef SICSEVENT #ifndef SICSEVENT
#define SICSEVENT #define SICSEVENT
#line 13 "event.w" #line 14 "event.w"
int Text2Event(char *pText); int Text2Event(char *pText);
#line 102 "event.w" #line 116 "event.w"
#line 20 "event.w" #line 21 "event.w"
#define VALUECHANGE 0 #define VALUECHANGE 0
#define MOTDRIVE 1 #define MOTDRIVE 1
@ -43,13 +43,17 @@
#define BATCHEND 16 #define BATCHEND 16
#define DRIVSTAT 17 #define DRIVSTAT 17
#define STATUS 18 #define STATUS 18
#define POSITION 19 /* Position event for motors - ffr */ #define POSITION 19
#line 104 "event.w" #define HDBVAL 20
#define STSTART 21
#define STEND 22
#line 118 "event.w"
/*--------------- Signals for the Signalfunction of each task ------------*/ /*--------------- Signals for the Signalfunction of each task ------------*/
#line 73 "event.w" #line 87 "event.w"
#define SICSINT 300 #define SICSINT 300
#define SICSBROADCAST 301 #define SICSBROADCAST 301
@ -57,6 +61,6 @@
#define TOKENRELEASE 303 #define TOKENRELEASE 303
#define COMLOG 304 #define COMLOG 304
#line 107 "event.w" #line 121 "event.w"
#endif #endif

View File

@ -53,6 +53,9 @@ $\langle$VE {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@#define BATCHAREA 15@\\ \mbox{}\verb@#define BATCHAREA 15@\\
\mbox{}\verb@#define BATCHEND 16@\\ \mbox{}\verb@#define BATCHEND 16@\\
\mbox{}\verb@#define DRIVSTAT 17@\\ \mbox{}\verb@#define DRIVSTAT 17@\\
\mbox{}\verb@#define STATUS 18@\\
\mbox{}\verb@#define POSITION 19@\\
\mbox{}\verb@#define HDBVAL 20@\\
\mbox{}\verb@@$\diamond$ \mbox{}\verb@@$\diamond$
\end{list} \end{list}
\vspace{-1ex} \vspace{-1ex}
@ -87,6 +90,10 @@ operation.
\item[BATCHEND] signals the end of the batch buffers processing. \item[BATCHEND] signals the end of the batch buffers processing.
\item[DRIVSTAT] signals a change in the status of a driving operation \item[DRIVSTAT] signals a change in the status of a driving operation
(start, finished, fault) (start, finished, fault)
\item[STATUS] ANSTO defined code.
\item[POSITION] ANSTO defined code
\item[HDBVAL] The Hdb is notified of a value change. The eventData will be
the object on which the data changed.
\end{description} \end{description}
Furthermore event contains system wide signal codes which are interpreted in Furthermore event contains system wide signal codes which are interpreted in

View File

@ -36,6 +36,9 @@ if the event code is not known, else the apropriate event code.
#define BATCHAREA 15 #define BATCHAREA 15
#define BATCHEND 16 #define BATCHEND 16
#define DRIVSTAT 17 #define DRIVSTAT 17
#define STATUS 18
#define POSITION 19
#define HDBVAL 20
@} @}
\begin{description} \begin{description}
\item[VALUECHANGE] This is a variable changing its value. As event data a pointer to the \item[VALUECHANGE] This is a variable changing its value. As event data a pointer to the
@ -62,6 +65,10 @@ operation.
\item[BATCHEND] signals the end of the batch buffers processing. \item[BATCHEND] signals the end of the batch buffers processing.
\item[DRIVSTAT] signals a change in the status of a driving operation \item[DRIVSTAT] signals a change in the status of a driving operation
(start, finished, fault) (start, finished, fault)
\item[STATUS] ANSTO defined code.
\item[POSITION] ANSTO defined code
\item[HDBVAL] The Hdb is notified of a value change. The eventData will be
the object on which the data changed.
\end{description} \end{description}
Furthermore event contains system wide signal codes which are interpreted in Furthermore event contains system wide signal codes which are interpreted in

1
exe.w
View File

@ -173,6 +173,7 @@ int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
int runExeBatchBuffer(void *pData, SConnection *pCon, SicsInterp *pSics, int runExeBatchBuffer(void *pData, SConnection *pCon, SicsInterp *pSics,
char *name); char *name);
pDynString findBatchFile(SicsInterp *pSics, char *name);
@} @}
@o exeman.i -d @{ @o exeman.i -d @{

View File

@ -1,5 +1,5 @@
#line 209 "exe.w" #line 210 "exe.w"
/** /**
* Buffer handling code for the Exe Buffer batch file processing * Buffer handling code for the Exe Buffer batch file processing
@ -89,7 +89,7 @@
*/ */
char *exeBufName(pExeBuf self); char *exeBufName(pExeBuf self);
#line 222 "exe.w" #line 223 "exe.w"
#endif #endif

View File

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

View File

@ -175,6 +175,43 @@ static pDynString locateBatchBuffer(pExeMan self, char *name){
DeleteDynString(result); DeleteDynString(result);
return NULL; return NULL;
} }
/*-------------------------------------------------------------------
* Generate a full path name for the argument in the first
* directory of batch path
* -------------------------------------------------------------------*/
static int makeExePath(pExeMan self, SConnection *pCon, int argc, char *argv[]){
char buffer[512], *pPtr = NULL, pPath[132];
if(argc < 3) {
SCWrite(pCon,"ERROR: require a file name for makepath",eError);
return 0;
}
strcpy(buffer,"exe.makepath = ");
/*
* do nothing to absolute path
*/
if(argv[2][0] == '/'){
strncat(buffer,argv[2],511-strlen(buffer));
SCWrite(pCon,buffer,eValue);
return 1;
}
pPtr = self->batchPath;
pPtr = stptok(pPtr,pPath,131,":");
strncat(buffer,pPath,511-strlen(buffer));
strncat(buffer,"/",511-strlen(buffer));
strncat(buffer,argv[2],511-strlen(buffer));
SCWrite(pCon,buffer,eValue);
return 1;
}
/*--------------------------------------------------------------------*/
pDynString findBatchFile(SicsInterp *pSics, char *name){
pExeMan self = (pExeMan)FindCommandData(pSics,"exe","ExeManager");
if(self == NULL){
return NULL;
}
return locateBatchBuffer(self,name);
}
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
static int runBatchBuffer(pExeMan self, SConnection *pCon, static int runBatchBuffer(pExeMan self, SConnection *pCon,
SicsInterp *pSics, char *name){ SicsInterp *pSics, char *name){
@ -937,6 +974,7 @@ int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
char pBufferName[256]; char pBufferName[256];
int status; int status;
pDynString dirList = NULL; pDynString dirList = NULL;
pDynString fullPath = NULL;
self = (pExeMan)pData; self = (pExeMan)pData;
assert(self != NULL); assert(self != NULL);
@ -1012,6 +1050,24 @@ int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
SCWrite(pCon,"Nothing found",eValue); SCWrite(pCon,"Nothing found",eValue);
} }
return 1; return 1;
}else if(strcmp(argv[1],"fullpath") == 0){
if(argc < 2){
SCWrite(pCon,"ERROR: not enough arguments to exe fullpath",eError);
return 0;
}
fullPath = locateBatchBuffer(self,argv[2]);
if(fullPath == NULL){
SCWrite(pCon,"ERROR: buffer NOT found",eError);
return 0;
} else {
DynStringInsert(fullPath,"exe.fullpath=",0);
SCWrite(pCon,GetCharArray(fullPath),eValue);
DeleteDynString(fullPath);
return 1;
}
return 1;
}else if(strcmp(argv[1],"makepath") == 0){
return makeExePath(self,pCon,argc,argv);
}else if(strcmp(argv[1],"clear") == 0){ }else if(strcmp(argv[1],"clear") == 0){
clearQueue(self); clearQueue(self);
SCSendOK(pCon); SCSendOK(pCon);

View File

@ -15,5 +15,6 @@ int ExeManagerWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
int runExeBatchBuffer(void *pData, SConnection *pCon, SicsInterp *pSics, int runExeBatchBuffer(void *pData, SConnection *pCon, SicsInterp *pSics,
char *name); char *name);
pDynString findBatchFile(SicsInterp *pSics, char *name);
#endif #endif

View File

@ -1,5 +1,5 @@
#line 178 "exe.w" #line 179 "exe.w"
/*------------------------------------------------------------------- /*-------------------------------------------------------------------
Internal header file for the exe manager module. Do not edit. This Internal header file for the exe manager module. Do not edit. This
@ -20,5 +20,5 @@ typedef struct __EXEMAN{
int echo; int echo;
}ExeMan, *pExeMan; }ExeMan, *pExeMan;
#line 183 "exe.w" #line 184 "exe.w"

View File

@ -421,6 +421,7 @@
pFit self = NULL; pFit self = NULL;
int iRet; int iRet;
char pBueffel[256]; char pBueffel[256];
pDynString buf = NULL;
self = (pFit)pData; self = (pFit)pData;
assert(self); assert(self);
@ -467,9 +468,17 @@
SCWrite(pCon,pBueffel,eValue); SCWrite(pCon,pBueffel,eValue);
return 1; return 1;
} }
if(strcmp(argv[1],"data") == 0)
{
snprintf(pBueffel,255,"%f,%f,%ld",
self->fCenter, self->FWHM, self->lPeak);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
} }
/* print results */ /* print results */
SCStartBuffering(pCon);
sprintf(pBueffel,"Estimated Peak Center: %f, StdDev: %f \n", sprintf(pBueffel,"Estimated Peak Center: %f, StdDev: %f \n",
self->fCenter,self->fStddev); self->fCenter,self->fStddev);
SCWrite(pCon,pBueffel,eValue); SCWrite(pCon,pBueffel,eValue);
@ -477,6 +486,10 @@
SCWrite(pCon,pBueffel,eValue); SCWrite(pCon,pBueffel,eValue);
sprintf(pBueffel,"Approximate FWHM: %f\n",self->FWHM); sprintf(pBueffel,"Approximate FWHM: %f\n",self->FWHM);
SCWrite(pCon,pBueffel,eValue); SCWrite(pCon,pBueffel,eValue);
buf = SCEndBuffering(pCon);
if(buf != NULL){
SCWrite(pCon,GetCharArray(buf),eValue);
}
return 1; return 1;
} }

View File

@ -625,6 +625,10 @@ int findAllowedBisecting(double lambda, MATRIX z1, float fSet[4],
return 0; return 0;
} }
if(testFunc(userData, fSet, mask) == 1){
return 1;
}
for(psi = .0; psi < 360.; psi += .5){ for(psi = .0; psi < 360.; psi += .5){
rotatePsi(om,chi,phi,psi,&ompsi,&chipsi,&phipsi); rotatePsi(om,chi,phi,psi,&ompsi,&chipsi,&phipsi);
fTest[0] = stt; fTest[0] = stt;
@ -638,6 +642,26 @@ int findAllowedBisecting(double lambda, MATRIX z1, float fSet[4],
} }
return 1; return 1;
} }
/*
* if chi close to 0, or 180, try to wrap phi onto om
*/
if(ABS(fTest[2] - .0) < .1 || ABS(fTest[2] - 180.) < .1){
fTest[1] -= fTest[3];
fTest[3] = .0;
if(fTest[1] < 0.){
fTest[1] += 360.;
}
if(fTest[1] > 360.0){
fTest[1] -= 360.;
}
status = testFunc(userData,fTest,mask);
if(status == 1){
for(i = 0; i < 4; i++){
fSet[i] = fTest[i];
}
return 1;
}
}
if(mask[0] == 0) { if(mask[0] == 0) {
/* /*
* useless: when two theta problem there is no solution * useless: when two theta problem there is no solution

291
hdbcommand.c Normal file
View File

@ -0,0 +1,291 @@
/**
* This module implements a generalized scheme for executing functions.
* Functions are described by a special data structure containing the
* parameters as a Hipadaba list and and an execute function which implements
* the actual operation. This is augmented by list mechanisms in order to
* allow for a list of functions. This shall facilitate a couple of things:
* - when functions are defined in such a structured form, general invocation
* functions can be devised for handling the interpreter interface.
* - The set of functions of an object can be configured and extended at
* runtime.
* - A common usage case: execute a function with the same arguments, can be
* easily catered for.
* All this is not new and was pioneered in the language self or other
* dynamic object systems.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, September 2006
*/
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <hdbcommand.h>
/*-------------------------------------------------------------------------*/
static int debug = 1;
/* ============================= live and death ============================*/
pHdbCommand CreateHdbCommand(char *name, int (*execute)(pHdb parameters)){
pHdbCommand result = NULL;
assert(name != NULL);
assert(execute != NULL);
result = malloc(sizeof(hdbCommand));
if(result == NULL){
return NULL;
}
memset(result,0,sizeof(hdbCommand));
result->name = strdup(name);
if(result->name == NULL){
free(result);
return NULL;
}
result->execute = execute;
return result;
}
/*--------------------------------------------------------------------------*/
void AppendHdbCommandToList(pHdbCommand commandList, pHdbCommand command){
pHdbCommand current = NULL;
assert(commandList != NULL);
assert(command != NULL);
current = commandList;
while(current->next != NULL){
current = (pHdbCommand)current->next;
}
command->previous = (struct __hdbCommand *)current;
current->next = (struct __hdbCommand *)command;
command->next = NULL;
}
/*--------------------------------------------------------------------------*/
void AppendCommandParameter(pHdbCommand command, pHdb par){
assert(command != NULL);
assert(par != NULL);
AddHipadabaChild(command->parameters,par,NULL);
}
/*--------------------------------------------------------------------------*/
void KillHdbCommandList(pHdbCommand commandList){
pHdbCommand next = NULL, current = NULL;
assert(commandList != NULL);
current = commandList;
next = (pHdbCommand)current->next;
while(current != NULL){
if(current->name != NULL){
free(current->name);
}
if(current->parameters != NULL){
DeleteHipadabaNode(current->parameters,NULL);
}
free(current);
current = next;
if(current != NULL){
next = (pHdbCommand)current->next;
} else {
next = NULL;
}
}
}
/*======================= Invocation =======================================*/
static pHdbCommand locateCommand(pHdbCommand commandList, char *name){
pHdbCommand current = NULL;
current = commandList;
while(current != NULL){
if(strcmp(current->name,name) == 0) {
return current;
}
current = (pHdbCommand)current->next;
}
return NULL;
}
/*---------------------------------------------------------------------------*/
int HdbCommandInvoke(pHdbCommand commandList, char *name, ...){
va_list ap;
pHdbCommand toInvoke = NULL;
pHdb currentPar = NULL;
char *txt = NULL;
hdbValue *v = NULL;
va_start(ap,name);
toInvoke = locateCommand(commandList,name);
if(toInvoke == NULL){
return HDBCOMNOCOM;
}
currentPar = toInvoke->parameters;
while(currentPar != NULL){
/*
* I cannot call a function for this as ap would be undefined after
* a call to a function here
*/
switch(currentPar->value.dataType){
case HIPNONE:
break;
case HIPINT:
currentPar->value.v.intValue = va_arg(ap,int);
if(debug == 1){
printf("Read %d for parameter %s\n",
currentPar->value.v.intValue, currentPar->name);
}
break;
case HIPFLOAT:
currentPar->value.v.doubleValue = va_arg(ap,double);
if(debug == 1){
printf("Read %lf for parameter %s\n",
currentPar->value.v.doubleValue, currentPar->name);
}
break;
case HIPTEXT:
txt = va_arg(ap,char *);
if(currentPar->value.v.text != NULL){
free(currentPar->value.v.text);
}
currentPar->value.v.text = strdup(txt);
if(debug == 1){
printf("Read %s for parameter %s\n",
currentPar->value.v.text, currentPar->name);
}
break;
case HIPOBJ:
currentPar->value.v.obj = va_arg(ap,void *);
break;
case HIPINTAR:
case HIPINTVARAR:
case HIPFLOATAR:
case HIPFLOATVARAR:
v = (hdbValue *)va_arg(ap,void *);
copyHdbValue(v,&currentPar->value);
break;
default:
assert(0);
break;
}
currentPar = currentPar->next;
}
va_end(ap);
return toInvoke->execute(toInvoke->parameters);
}
/*-------------------------------------------------------------------------*/
static void *(*objMap)(char *name) = NULL;
/*-------------------------------------------------------------------------*/
void SetHdbComObjMapper(void *(*mapObj)(char *name)){
objMap = mapObj;
}
/*-------------------------------------------------------------------------*/
static int readParArguments(pHdb parNode, int argc, char *argv[]){
int i, intVal;
double doVal;
switch(parNode->value.dataType){
case HIPNONE:
return 0;
break;
case HIPINT:
if(argc < 1){
return HDBCOMNOARGS;
}
if(sscanf(argv[0],"%d",&parNode->value.v.intValue) != 1){
return HDBCOMBADARG;
}
return 1;
break;
case HIPFLOAT:
if(argc < 1){
return HDBCOMNOARGS;
}
if(sscanf(argv[0],"%lf",&parNode->value.v.doubleValue) != 1){
return HDBCOMBADARG;
}
return 1;
break;
case HIPOBJ:
if(objMap != NULL){
parNode->value.v.obj = objMap(argv[0]);
if(parNode->value.v.obj == NULL){
return HDBCOMBADOBJ;
} else {
return 1;
}
}
return 0;
break;
case HIPTEXT:
if(argc < 1){
return HDBCOMNOARGS;
}
if(parNode->value.v.text != NULL){
free(parNode->value.v.text);
}
parNode->value.v.text = strdup(argv[0]);
return 1;
break;
case HIPINTAR:
if(parNode->value.arrayLength > argc){
return HDBCOMNOARGS;
}
for(i = 0; i < parNode->value.arrayLength; i++){
if(sscanf(argv[i],"%d",&intVal) != 1){
return HDBCOMBADARG;
}
parNode->value.v.intArray[i] = intVal;
}
return parNode->value.arrayLength;
break;
case HIPFLOATAR:
if(parNode->value.arrayLength > argc){
return HDBCOMNOARGS;
}
for(i = 0; i < parNode->value.arrayLength; i++){
if(sscanf(argv[i],"%lf",&doVal) != 1){
return HDBCOMBADARG;
}
parNode->value.v.floatArray[i] = doVal;
}
return parNode->value.arrayLength;
break;
default:
/*
* I cannot process such variables
*/
return HDBCOMINVARG;
break;
}
return 0;
}
/*--------------------------------------------------------------------------*/
int HdbCommandTextInvoke(pHdbCommand commandList, int argc, char *argv[]){
pHdbCommand toInvoke = NULL;
pHdb currentPar = NULL;
int argPointer, status;
assert(commandList != NULL);
if(argc < 1){
return HDBCOMNOARGS;
}
toInvoke = locateCommand(commandList,argv[0]);
if(toInvoke == NULL){
return HDBCOMNOCOM;
}
currentPar = toInvoke->parameters;
argPointer = 1;
while(currentPar != NULL){
status = readParArguments(currentPar,argc-argPointer,
&argv[argPointer]);
if(status < 0){
return status;
} else {
argPointer += status;
}
currentPar = currentPar->next;
}
return toInvoke->execute(toInvoke->parameters);
}

96
hdbcommand.h Normal file
View File

@ -0,0 +1,96 @@
/**
* This module implements a generalized scheme for executing functions.
* Functions are described by a special data structure containing the
* parameters as a Hipadaba list and and an execute function which implements
* the actual operation. This is augmented by list mechanisms in order to
* allow for a list of functions. This shall facilitate a couple of things:
* - when functions are defined in such a structured form, general invocation
* functions can be devised for handling the interpreter interface.
* - The set of functions of an object can be configured and extended at
* runtime.
* - A common usage case: execute a function with the same arguments, can be
* easily catered for.
* All this is not new and was pioneered in the language self or other
* dynamic object systems.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, September 2006
*/
#ifndef HDBCOMMAND_H_
#define HDBCOMMAND_H_
#include <stdarg.h>
#include <hipadaba.h>
/*--------------- error codes ----------------------------------------------*/
#define HDCOMNOMEM -7801
#define HDBCOMNOCOM -7802
#define HDBCOMNOARGS -7803
#define HDBCOMBADARG -7804
#define HDBCOMINVARG -7805
#define HDBCOMBADOBJ -7806
/*---------------------------------------------------------------------------*/
typedef struct __hdbCommmand {
char *name;
pHdb parameters;
int (*execute)(pHdb parameters);
struct __hdbCommand *next;
struct __hdbCommand *previous;
}hdbCommand, *pHdbCommand;
/*======================= live and death ===================================*/
/**
* create a hdbCommand with an empty parameter list
* @param name The name of teh command
* @param execute The execute function for this command
* @return a fresh hdbCommand or NULL when out of memory
* */
pHdbCommand CreateHdbCommand(char *name, int (*execute)(pHdb parameters));
/**
* append a hdbCommand to a command list
* @param commandList The list to append the command to
* @param command The command to append
* @return 1 on success, a negative error code else.
*/
void AppendHdbCommandToList(pHdbCommand commandList, pHdbCommand command);
/**
* append a parameter to the parameter list
* @param command The command to append the parameter too
* @param par The parameter to append
*/
void AppendCommandParameter(pHdbCommand command, pHdb par);
/**
* delete a command list recursively
* @param commandList The command list to delete
*/
void KillHdbCommandList(pHdbCommand commandList);
/*===================== invocation ========================================*/
/**
* invoke a hdbCommand name. This does a lot: it locates the command,
* it assigne the parameter values and finally calls the execute function.
* @param commandList The command list in which to search for the command
* @param name The name of the command
* @param ... arguments to the command. ints, double, text and objects (pointers)
* are accepted as is.Arrays have to be passed in a pointers to a
* hdbValue structure. Otherwise there is not eonough information to safely
* copy array data.
* @return Negative error codes on invocation error, else the return
* value of the execute function.
*/
int HdbCommandInvoke(pHdbCommand commandList, char *name, ...);
/**
* invoke a hdbCommand name. This does a lot: it locates the command,
* it assigne the parameter values and finally calls the execute function.
* The name of the command must be in argv[0]
* @param commandList The command list in which to search for the command
* @param argc The number of arguments
* @param argv[] An array of strings holding the argument data
* @return Negative error codes on invocation error, else the return
* value of the execute function.
*/
int HdbCommandTextInvoke(pHdbCommand commandList, int argc, char *argv[]);
/**
* set a mapper which returns a void pointer for a name in order to resolve
* object references
* @param mapfunc
*/
void SetHdbComObjMapper(void *(*mapObj)(char *name));
#endif /*HDBCOMMAND_H_*/

View File

@ -38,6 +38,10 @@ static void DeleteNodeData(pHdb node){
DeleteCallbackChain(node->writeCallbacks); DeleteCallbackChain(node->writeCallbacks);
DeleteCallbackChain(node->updateCallbacks); DeleteCallbackChain(node->updateCallbacks);
DeleteCallbackChain(node->readCallbacks); DeleteCallbackChain(node->readCallbacks);
DeleteCallbackChain(node->treeChangeCallbacks);
if(node->properties != NULL){
DeleteStringDict(node->properties);
}
if(node->name != NULL){ if(node->name != NULL){
free(node->name); free(node->name);
@ -52,8 +56,24 @@ static void DeleteNodeData(pHdb node){
} }
free(node); free(node);
} }
/*-------------------------------------------------------------------------*/
static int InvokeCallbackChain(pHdbCallback root, pHdb node,
void *callData, hdbValue v){
pHdbCallback current = root;
int status;
while(current != NULL){
status = current->userCallback(current->userData,callData,
node,v);
if(status != 1){
return status;
}
current = current->next;
}
return 1;
}
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
void RemoveHdbNodeFromParent(pHdb node){ void RemoveHdbNodeFromParent(pHdb node, void *callData){
pHdb parent = NULL; pHdb parent = NULL;
pHdb current = NULL; pHdb current = NULL;
@ -68,6 +88,8 @@ void RemoveHdbNodeFromParent(pHdb node){
current = current->next; current = current->next;
} }
current->next = current->next->next; current->next = current->next->next;
InvokeCallbackChain(parent->treeChangeCallbacks,
parent,callData,parent->value);
} }
} }
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -174,22 +196,6 @@ static pHdbCallback DeleteForInternalID(pHdbCallback root, int id){
} }
return result; return result;
} }
/*-------------------------------------------------------------------------*/
static int InvokeCallbackChain(pHdbCallback root, pHdb node,
void *callData, hdbValue v){
pHdbCallback current = root;
int status;
while(current != NULL){
status = current->userCallback(current->userData,callData,
node,v);
if(status != 1){
return status;
}
current = current->next;
}
return 1;
}
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
char *hdbTrim(char *str) char *hdbTrim(char *str)
{ {
@ -270,9 +276,9 @@ hdbValue makeHdbValue(int datatype, int length){
case HIPINTAR: case HIPINTAR:
case HIPINTVARAR: case HIPINTVARAR:
val.arrayLength = length; val.arrayLength = length;
val.v.intArray = malloc(length*sizeof(long)); val.v.intArray = malloc(length*sizeof(int));
if(val.v.intArray != NULL){ if(val.v.intArray != NULL){
memset(val.v.intArray,0,length*sizeof(long)); memset(val.v.intArray,0,length*sizeof(int));
} }
break; break;
case HIPFLOATAR: case HIPFLOATAR:
@ -285,6 +291,61 @@ hdbValue makeHdbValue(int datatype, int length){
break; break;
case HIPTEXT: case HIPTEXT:
val.v.text = strdup("UNKNOWN"); val.v.text = strdup("UNKNOWN");
val.arrayLength = length;
break;
}
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; break;
} }
return val; return val;
@ -294,6 +355,7 @@ hdbValue MakeHdbInt(int initValue){
hdbValue result; hdbValue result;
result.dataType = HIPINT; result.dataType = HIPINT;
result.arrayLength = 1;
result.v.intValue = initValue; result.v.intValue = initValue;
return result; return result;
} }
@ -302,6 +364,7 @@ hdbValue MakeHdbFloat(double initValue){
hdbValue result; hdbValue result;
result.dataType = HIPFLOAT; result.dataType = HIPFLOAT;
result.arrayLength = 1;
result.v.doubleValue = initValue; result.v.doubleValue = initValue;
return result; return result;
} }
@ -311,10 +374,11 @@ hdbValue MakeHdbText(char *initText){
result.dataType = HIPTEXT; result.dataType = HIPTEXT;
result.v.text = initText; result.v.text = initText;
result.arrayLength = strlen(initText);
return result; return result;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
hdbValue MakeHdbIntArray(int length, long *data){ hdbValue MakeHdbIntArray(int length, int *data){
hdbValue result; hdbValue result;
result.dataType = HIPINTAR; result.dataType = HIPINTAR;
@ -409,6 +473,13 @@ int compareHdbValue(hdbValue v1, hdbValue v2){
} }
return 1; return 1;
break; break;
case HIPOBJ:
if(v2.v.obj == v1.v.obj) {
return 1;
} else {
return 0;
}
break;
default: default:
assert(0); assert(0);
break; break;
@ -422,6 +493,35 @@ int cloneHdbValue(hdbValue *source, hdbValue *clone){
clone->dataType = source->dataType; clone->dataType = source->dataType;
return copyHdbValue(source, clone); return copyHdbValue(source, clone);
} }
/*-------------------------------------------------------------------------*/
int getHdbValueLength(hdbValue v){
int length = 0;
switch(v.dataType){
case HIPNONE:
break;
case HIPINT:
length = sizeof(int);
break;
case HIPFLOAT:
length = sizeof(double);
break;
case HIPINTAR:
case HIPINTVARAR:
length = v.arrayLength * sizeof(int);
break;
case HIPFLOATAR:
case HIPFLOATVARAR:
length = v.arrayLength * sizeof(double);
break;
case HIPTEXT:
length = strlen(v.v.text);
break;
case HIPOBJ:
length = sizeof(void *);
break;
}
return length;
}
/*================= node functions ========================================*/ /*================= node functions ========================================*/
pHdb MakeHipadabaNode(char *name, int datatype, int length){ pHdb MakeHipadabaNode(char *name, int datatype, int length){
pHdb pNew = NULL; pHdb pNew = NULL;
@ -434,15 +534,19 @@ pHdb MakeHipadabaNode(char *name, int datatype, int length){
pNew->magic = HDBMAGICK; pNew->magic = HDBMAGICK;
pNew->name = strdup(name); pNew->name = strdup(name);
pNew->value.dataType = datatype; pNew->value.dataType = datatype;
pNew->properties = CreateStringDict();
if(pNew->properties == NULL || pNew->name == NULL){
return NULL;
}
switch(datatype){ switch(datatype){
case HIPINTAR: case HIPINTAR:
case HIPINTVARAR: case HIPINTVARAR:
pNew->value.arrayLength = length; pNew->value.arrayLength = length;
pNew->value.v.intArray = malloc(length*sizeof(long)); pNew->value.v.intArray = malloc(length*sizeof(int));
if(pNew->value.v.intArray == NULL){ if(pNew->value.v.intArray == NULL){
return NULL; return NULL;
} }
memset(pNew->value.v.intArray,0,length*sizeof(long)); memset(pNew->value.v.intArray,0,length*sizeof(int));
break; break;
case HIPFLOATAR: case HIPFLOATAR:
case HIPFLOATVARAR: case HIPFLOATVARAR:
@ -454,16 +558,20 @@ pHdb MakeHipadabaNode(char *name, int datatype, int length){
memset(pNew->value.v.floatArray,0,length*sizeof(double)); memset(pNew->value.v.floatArray,0,length*sizeof(double));
break; break;
case HIPTEXT: case HIPTEXT:
pNew->value.arrayLength = length;
pNew->value.v.text = strdup("UNKNOWN"); pNew->value.v.text = strdup("UNKNOWN");
break; break;
} }
return pNew; return pNew;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
void AddHipadabaChild(pHdb parent, pHdb child){ void AddHipadabaChild(pHdb parent, pHdb child, void *callData){
pHdb current = NULL, prev = NULL; pHdb current = NULL, prev = NULL;
assert(parent != NULL && child != NULL); assert(parent != NULL);
if(child == NULL){
return;
}
current = parent->child; current = parent->child;
child->mama = parent; child->mama = parent;
@ -481,16 +589,18 @@ void AddHipadabaChild(pHdb parent, pHdb child){
child->next = NULL; child->next = NULL;
prev->next = child; prev->next = child;
} }
InvokeCallbackChain(parent->treeChangeCallbacks,
parent,callData,parent->value);
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
void DeleteHipadabaNode(pHdb node){ void DeleteHipadabaNode(pHdb node, void *callData){
pHdb current = NULL, tmp = NULL; pHdb current = NULL, tmp = NULL;
if(node == NULL){ if(node == NULL){
return; return;
} }
RemoveHdbNodeFromParent(node); RemoveHdbNodeFromParent(node, callData);
DeleteNodeData(node); DeleteNodeData(node);
} }
@ -637,6 +747,14 @@ void AppendHipadabaCallback(pHdb node, int type, pHdbCallback newCB){
current = node->readCallbacks; current = node->readCallbacks;
} }
break; break;
case HCBTREE:
if(node->treeChangeCallbacks == NULL){
node->treeChangeCallbacks = newCB;
return;
} else {
current = node->treeChangeCallbacks;
}
break;
default: default:
assert(0); assert(0);
break; break;
@ -649,7 +767,6 @@ void AppendHipadabaCallback(pHdb node, int type, pHdbCallback newCB){
newCB->previous = current; newCB->previous = current;
} }
} }
/*-------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void PrependHipadabaCallback(pHdb node, int type, pHdbCallback newCB){ void PrependHipadabaCallback(pHdb node, int type, pHdbCallback newCB){
switch(type){ switch(type){
@ -683,6 +800,16 @@ void PrependHipadabaCallback(pHdb node, int type, pHdbCallback newCB){
node->readCallbacks = newCB; node->readCallbacks = newCB;
} }
break; 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: default:
assert(0); assert(0);
break; break;
@ -695,6 +822,7 @@ void RemoveHipadabaCallback(pHdb root, int id){
root->writeCallbacks = DeleteForID(root->writeCallbacks,id); root->writeCallbacks = DeleteForID(root->writeCallbacks,id);
root->updateCallbacks = DeleteForID(root->updateCallbacks,id); root->updateCallbacks = DeleteForID(root->updateCallbacks,id);
root->readCallbacks = DeleteForID(root->readCallbacks,id); root->readCallbacks = DeleteForID(root->readCallbacks,id);
root->treeChangeCallbacks = DeleteForID(root->treeChangeCallbacks,id);
current = root->child; current = root->child;
while(current != NULL){ while(current != NULL){
@ -709,6 +837,7 @@ void InternalRemoveHipadabaCallback(pHdb root, int internalID){
root->writeCallbacks = DeleteForInternalID(root->writeCallbacks,internalID); root->writeCallbacks = DeleteForInternalID(root->writeCallbacks,internalID);
root->updateCallbacks = DeleteForInternalID(root->updateCallbacks,internalID); root->updateCallbacks = DeleteForInternalID(root->updateCallbacks,internalID);
root->readCallbacks = DeleteForInternalID(root->readCallbacks,internalID); root->readCallbacks = DeleteForInternalID(root->readCallbacks,internalID);
root->treeChangeCallbacks = DeleteForInternalID(root->treeChangeCallbacks,internalID);
current = root->child; current = root->child;
while(current != NULL){ while(current != NULL){
@ -741,24 +870,26 @@ int copyHdbValue(hdbValue *source, hdbValue *target){
break; break;
case HIPINTAR: case HIPINTAR:
case HIPINTVARAR: case HIPINTVARAR:
if(target->arrayLength != source->arrayLength){ if(target->arrayLength != source->arrayLength || target->v.intArray == NULL){
if(target->v.intArray != NULL){ if(target->v.intArray != NULL){
free(target->v.intArray); free(target->v.intArray);
} }
target->v.intArray = malloc(source->arrayLength * sizeof(long)); target->v.intArray = malloc(source->arrayLength * sizeof(int));
if(target->v.intArray == NULL){ if(target->v.intArray == NULL){
return 0; return 0;
} }
memset(target->v.intArray,0,source->arrayLength * sizeof(long)); memset(target->v.intArray,0,source->arrayLength * sizeof(int));
target->arrayLength = source->arrayLength; target->arrayLength = source->arrayLength;
} }
if(source->v.intArray != NULL){
for(i = 0; i < source->arrayLength; i++){ for(i = 0; i < source->arrayLength; i++){
target->v.intArray[i] = source->v.intArray[i]; target->v.intArray[i] = source->v.intArray[i];
} }
}
break; break;
case HIPFLOATAR: case HIPFLOATAR:
case HIPFLOATVARAR: case HIPFLOATVARAR:
if(target->arrayLength != source->arrayLength){ if(target->arrayLength != source->arrayLength || target->v.floatArray == NULL){
if(target->v.floatArray != NULL){ if(target->v.floatArray != NULL){
free(target->v.floatArray); free(target->v.floatArray);
} }
@ -769,9 +900,14 @@ int copyHdbValue(hdbValue *source, hdbValue *target){
memset(target->v.floatArray,0,source->arrayLength * sizeof(double)); memset(target->v.floatArray,0,source->arrayLength * sizeof(double));
target->arrayLength = source->arrayLength; target->arrayLength = source->arrayLength;
} }
if(source->v.floatArray != NULL){
for(i = 0; i < source->arrayLength; i++){ for(i = 0; i < source->arrayLength; i++){
target->v.floatArray[i] = source->v.floatArray[i]; target->v.floatArray[i] = source->v.floatArray[i];
} }
}
break;
case HIPOBJ:
target->v.obj = source->v.obj;
break; break;
default: default:
/* /*
@ -812,4 +948,149 @@ int GetHipadabaPar(pHdb node, hdbValue *v, void *callData){
copyHdbValue(&node->value,v); copyHdbValue(&node->value,v);
return 1; return 1;
} }
/*----------------------------------------------------------------------------*/
static int calcDataLength(pHdb node, int testLength){
int length = 0;
length = getHdbValueLength(node->value);
if(node->value.dataType == HIPFLOATVARAR ||
node->value.dataType == HIPINTVARAR ||
node->value.dataType == HIPTEXT){
length = 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)){
StringDictUpdate(node->properties,key,value);
} else {
StringDictAddPair(node->properties,key,value);
}
}
}
/*---------------------------------------------------------------------------*/
int GetHdbProperty(pHdb node, char *key, char *value, int len){
if(node != NULL && node->properties != NULL){
return StringDictGet(node->properties,key,value,len);
} else {
return 0;
}
}
/*---------------------------------------------------------------------------*/
void InitHdbPropertySearch(pHdb node){
if(node != NULL && node->properties != NULL){
StringDictKillScan(node->properties);
}
}
/*--------------------------------------------------------------------------*/
const char *GetNextHdbProperty(pHdb node, char *value ,int len){
if(node != NULL && node->properties != NULL) {
return StringDictGetNext(node->properties, value, len);
} else {
return NULL;
}
}

View File

@ -20,9 +20,14 @@
* copyright: GPL * copyright: GPL
* *
* Mark Koennecke, June 2006 * Mark Koennecke, June 2006
*
* Added treeChange callback, Mark Koennecke, November 2006
*
* Added support for properties, Mark Koennecke, January 2007
*/ */
#ifndef HIPADABA #ifndef HIPADABA
#define HIPADABA #define HIPADABA
#include <stringdict.h>
/*------- datatypes */ /*------- datatypes */
#define HIPNONE -1 #define HIPNONE -1
@ -33,20 +38,26 @@
#define HIPFLOATAR 4 #define HIPFLOATAR 4
#define HIPINTVARAR 5 #define HIPINTVARAR 5
#define HIPFLOATVARAR 6 #define HIPFLOATVARAR 6
#define HIPOBJ 7
/* -------- callback types */ /* -------- callback types */
#define HCBSET 0 #define HCBSET 0
#define HCBUPDATE 1 #define HCBUPDATE 1
#define HCBREAD 2 #define HCBREAD 2
#define HCBTREE 3
/*--------- error codes */
#define HDBTYPEMISMATCH -7701
#define HDBLENGTHMISMATCH -7702
/*===================== structure definitions ===================================*/ /*===================== structure definitions ===================================*/
typedef struct __hdbValue { typedef struct __hdbValue {
int dataType; int dataType;
int arrayLength; int arrayLength;
union __value { union __value {
long intValue; int intValue;
double doubleValue; double doubleValue;
char *text; char *text;
long *intArray; int *intArray;
double *floatArray; double *floatArray;
void *obj;
}v; }v;
}hdbValue; }hdbValue;
/*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------*/
@ -58,12 +69,15 @@ typedef struct __hipadaba {
struct __hdbcallback *writeCallbacks; struct __hdbcallback *writeCallbacks;
struct __hdbcallback *updateCallbacks; struct __hdbcallback *updateCallbacks;
struct __hdbcallback *readCallbacks; struct __hdbcallback *readCallbacks;
struct __hdbcallback *treeChangeCallbacks;
char *name; char *name;
hdbValue value; hdbValue value;
int protected;
pStringDict properties;
}Hdb, *pHdb; }Hdb, *pHdb;
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
typedef int (*hdbCallbackFunction)(void *userData, void *callData, typedef int (*hdbCallbackFunction)(void *userData, void *callData,
pHdb currentNode, hdbValue v ); pHdb currentNode, hdbValue v);
typedef void (*killUserData)(void *data); typedef void (*killUserData)(void *data);
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
typedef struct __hdbcallback { typedef struct __hdbcallback {
@ -77,6 +91,15 @@ typedef struct __hdbcallback {
}hdbCallback, *pHdbCallback; }hdbCallback, *pHdbCallback;
/*======================== Function protoypes: hdbData ========================*/ /*======================== Function protoypes: hdbData ========================*/
hdbValue makeHdbValue(int datatype, int length); hdbValue makeHdbValue(int datatype, int length);
/**
* 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
* @return a suitably defined hdbValue
*/
hdbValue makeHdbData(int datatype, int length, void *data);
/** /**
* wrap an integer as an hdbValue * wrap an integer as an hdbValue
* @param initValue the initial value of the int * @param initValue the initial value of the int
@ -107,7 +130,7 @@ hdbValue MakeHdbText(char *initText);
* data points to dynamically allocated memory. * data points to dynamically allocated memory.
* @return: A properly initialized hdbValue structure * @return: A properly initialized hdbValue structure
*/ */
hdbValue MakeHdbIntArray(int length, long *data); hdbValue MakeHdbIntArray(int length, int *data);
/** /**
* wrap a float array as an hdbValue * wrap a float array as an hdbValue
* @param length The length of the int array * @param length The length of the int array
@ -147,6 +170,12 @@ int compareHdbValue(hdbValue v1, hdbValue v2);
* @return 1 on success, 0 on when out of memory * @return 1 on success, 0 on when out of memory
*/ */
int cloneHdbValue(hdbValue *source, hdbValue *clone); int cloneHdbValue(hdbValue *source, hdbValue *clone);
/**
* get the length of the hdbValue in bytes.
* @param v The hdbValue to calculate the length for
* @return the number of data bytes
*/
int getHdbValueLength(hdbValue v);
/*========================== function protoypes: Nodes =======================*/ /*========================== function protoypes: Nodes =======================*/
/** /**
* make a new hipadaba node * make a new hipadaba node
@ -156,16 +185,18 @@ int cloneHdbValue(hdbValue *source, hdbValue *clone);
*/ */
pHdb MakeHipadabaNode(char *name, int datatype, int length); pHdb MakeHipadabaNode(char *name, int datatype, int length);
/** /**
* add a child to a node * add a child to a node at the end of the child list.
* @param parent The node to which to add the child * @param parent The node to which to add the child
* @param child The node to add * @param child The node to add
* @param callData User data for the tree chnage callback. Can be NULL.
*/ */
void AddHipadabaChild(pHdb parent, pHdb child); void AddHipadabaChild(pHdb parent, pHdb child, void *callData);
/** /**
* delete a hipadaba node and all its children * delete a hipadaba node and all its children
* @parma node The node to delete * @parma node The node to delete
* @param callData User data for the tree change callback
*/ */
void DeleteHipadabaNode(pHdb node); void DeleteHipadabaNode(pHdb node, void *callData);
/* /*
* checks if a Hdb node is valid * checks if a Hdb node is valid
* @param node The node to check * @param node The node to check
@ -189,8 +220,9 @@ char *GetHipadabaPath(pHdb node);
/** /**
* removes a node from the parents child list. * removes a node from the parents child list.
* @node the node to remove * @node the node to remove
* @param callData User data for the tree change callback
*/ */
void RemoveHdbNodeFromParent(pHdb node); void RemoveHdbNodeFromParent(pHdb node, void *callData);
/** /**
* delete a callback chain * delete a callback chain
* @param root The callback chain to delete * @param root The callback chain to delete
@ -250,8 +282,8 @@ void InternalRemoveHipadabaCallback(pHdb root, int internalID);
*/ */
int SetHipadabaPar(pHdb node, hdbValue v, void *callData); int SetHipadabaPar(pHdb node, hdbValue v, void *callData);
/** /**
* Update a hipadaba parameter. This is an internal update of a parameter, during * Update a hipadaba parameter. This is an internal update of a parameter,
* driving etc. * during driving etc.
* @param node The node for which to update the parameter * @param node The node for which to update the parameter
* @param v The new value for the node * @param v The new value for the node
* @param callData Additonal context data to be passed to the callback functions * @param callData Additonal context data to be passed to the callback functions
@ -266,5 +298,70 @@ int UpdateHipadabaPar(pHdb node, hdbValue v, void *callData);
* @return 0 on failure, 1 on success * @return 0 on failure, 1 on success
*/ */
int GetHipadabaPar(pHdb node, hdbValue *v, void *callData); 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
* @param node The node to set the property for
* @param key The key for the property
* @param value The value of the property
*/
void SetHdbProperty(pHdb node, char *key, char *value);
/**
* get the value of a property
* @param node The node to get the property from
* @param key The properties key
* @param value The area to which to copy the property
* @param len The length of value
* @return 0 on failure, 1 on success
*/
int GetHdbProperty(pHdb node, char *key, char *value, int len);
/**
* initialize a property scan on this node
* @param node The node for which to scan properties
*/
void InitHdbPropertySearch(pHdb node);
/**
* get the next property in a search
* @param node The node for which to search properties
* @param value An area where to copy the value of the property
* @param len The length of value
* @return The key of the property or NULL when the property list is exhausted
*/
const char *GetNextHdbProperty(pHdb node, char *value ,int len);
#endif #endif

View File

@ -68,6 +68,10 @@
/* /*
#define LOADDEBUG 1 #define LOADDEBUG 1
*/ */
/*
* from histregress.c
*/
extern pHistDriver CreateRegressHM(pStringDict pOpt);
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
static int HistHalt(void *pData) static int HistHalt(void *pData)
{ {
@ -171,6 +175,8 @@
iRet = self->pDriv->Start(self->pDriv, pCon); iRet = self->pDriv->Start(self->pDriv, pCon);
if(iRet == OKOK) if(iRet == OKOK)
{ {
/* send a COUNTSTART event */
InvokeCallBack(self->pCall,COUNTSTART,pCon);
updateHMData(self->pDriv->data); updateHMData(self->pDriv->data);
return iRet; return iRet;
} }
@ -452,6 +458,10 @@
{ {
pNew->pDriv = NewMcStasHM(pOption); pNew->pDriv = NewMcStasHM(pOption);
} }
else if(strcmp(driver,"regress") == 0)
{
pNew->pDriv = CreateRegressHM(pOption);
}
else else
{ {
site = getSite(); site = getSite();
@ -721,8 +731,6 @@ void HistDirty(pHistMem self)
{ {
assert(self); assert(self);
/* send a COUNTSTART event */
InvokeCallBack(self->pCall,COUNTSTART,pCon);
/* start */ /* start */
return StartDevice(GetExecutor(),"HistogramMemory", self->pDes, self, return StartDevice(GetExecutor(),"HistogramMemory", self->pDes, self,
@ -744,9 +752,6 @@ void HistDirty(pHistMem self)
return 0; return 0;
} }
/* send a COUNTSTART event */
InvokeCallBack(self->pCall,COUNTSTART,pCon);
/* wait till end */ /* wait till end */
iRet = Wait4Success(GetExecutor()); iRet = Wait4Success(GetExecutor());
if(iRet == DEVINT) if(iRet == DEVINT)
@ -1233,6 +1238,12 @@ static int checkHMEnd(pHistMem self, char *text){
} }
else if(strcmp(argv[1],"init") == 0) else if(strcmp(argv[1],"init") == 0)
{ {
if(GetStatus() != eEager)
{
SCWrite(pCon,"ERROR: cannot initialize HM while running",
eError);
return 0;
}
if(SCMatchRights(pCon,usMugger)) if(SCMatchRights(pCon,usMugger))
{ {
iRet = HistConfigure(self,pCon,pSics); iRet = HistConfigure(self,pCon,pSics);
@ -1357,6 +1368,31 @@ static int checkHMEnd(pHistMem self, char *text){
} }
return iRet; return iRet;
} }
else if(strcmp(argv[1],"initfile") == 0) /* initialize from a file */
{
/* check user rights */
if(!SCMatchRights(pCon,self->iAccess))
{
return 0;
}
/* enough arguments */
if(argc < 3)
{
sprintf(pBueffel,"ERROR: insufficient number of arguments to %s %s",
argv[0], argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
iRet = loadHMData(self->pDriv->data,pCon,argv[2]);
self->pDriv->SetHistogram(self->pDriv,pCon,0,0,GetHistLength(self),
self->pDriv->data->localBuffer);
if(iRet)
{
SCSendOK(pCon);
}
return iRet;
}
else if(strcmp(argv[1],"get") == 0) /* get a histogram */ else if(strcmp(argv[1],"get") == 0) /* get a histogram */
{ {
/* check parameters, first required: no of Hist */ /* check parameters, first required: no of Hist */
@ -1389,6 +1425,11 @@ static int checkHMEnd(pHistMem self, char *text){
iEnd = checkHMEnd(self,NULL); iEnd = checkHMEnd(self,NULL);
} }
if(iNum != 0 && argc > 4)
{
iEnd = atoi(argv[4]);
}
/* allocate data storage and get it */ /* allocate data storage and get it */
lData = (HistInt *)malloc(iEnd*sizeof(HistInt)); lData = (HistInt *)malloc(iEnd*sizeof(HistInt));
if(!lData) if(!lData)
@ -1397,8 +1438,14 @@ static int checkHMEnd(pHistMem self, char *text){
return 0; return 0;
} }
memset(lData,0,iEnd*sizeof(HistInt)); memset(lData,0,iEnd*sizeof(HistInt));
if(iNum == 0)
{
iRet = GetHistogram(self,pCon,iNum,iStart,iEnd, iRet = GetHistogram(self,pCon,iNum,iStart,iEnd,
lData,iEnd*sizeof(long)); lData,iEnd*sizeof(long));
} else {
iRet = GetHistogramDirect(self,pCon,iNum,iStart, iEnd,
lData, iEnd*sizeof(long));
}
if(!iRet) if(!iRet)
{ {
sprintf(pBueffel,"ERROR: cannot retrieve histogram %d",iNum); sprintf(pBueffel,"ERROR: cannot retrieve histogram %d",iNum);
@ -1565,10 +1612,10 @@ static int checkHMEnd(pHistMem self, char *text){
else if(strcmp(argv[1],"timebin") == 0) else if(strcmp(argv[1],"timebin") == 0)
{ {
Tcl_DStringInit(&tResult); Tcl_DStringInit(&tResult);
Tcl_DStringAppend(&tResult,"histogram.timebins = ",-1); Tcl_DStringAppend(&tResult,"histogram.timebins =",-1);
for(i = 0; i < self->pDriv->data->nTimeChan; i++) for(i = 0; i < self->pDriv->data->nTimeChan; i++)
{ {
sprintf(pBueffel," %8.2f", self->pDriv->data->timeBinning[i]); sprintf(pBueffel,"%.2f ", self->pDriv->data->timeBinning[i]);
Tcl_DStringAppend(&tResult,pBueffel,-1); Tcl_DStringAppend(&tResult,pBueffel,-1);
} }
/* Write it */ /* Write it */

View File

@ -163,6 +163,9 @@ $\langle$HistType {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ SConnection *pCon);@\\ \mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@ float (*GetTime)(pHistDriver self,@\\ \mbox{}\verb@ float (*GetTime)(pHistDriver self,@\\
\mbox{}\verb@ SConnection *pCon);@\\ \mbox{}\verb@ SConnection *pCon);@\\
\mbox{}\verb@ HistInt *(*SubSample)(pHistDriver self, @\\
\mbox{}\verb@ SConnection *pCon,int bank,@\\
\mbox{}\verb@ char *command); @\\
\mbox{}\verb@ int (*Preset)(pHistDriver self,@\\ \mbox{}\verb@ int (*Preset)(pHistDriver self,@\\
\mbox{}\verb@ SConnection *pCon,@\\ \mbox{}\verb@ SConnection *pCon,@\\
\mbox{}\verb@ HistInt iVal);@\\ \mbox{}\verb@ HistInt iVal);@\\

View File

@ -130,6 +130,9 @@ definition:
SConnection *pCon); SConnection *pCon);
float (*GetTime)(pHistDriver self, float (*GetTime)(pHistDriver self,
SConnection *pCon); SConnection *pCon);
HistInt *(*SubSample)(pHistDriver self,
SConnection *pCon,int bank,
char *command);
int (*Preset)(pHistDriver self, int (*Preset)(pHistDriver self,
SConnection *pCon, SConnection *pCon,
HistInt iVal); HistInt iVal);

273
histregress.c Normal file
View File

@ -0,0 +1,273 @@
/*----------------------------------------------------------------------------
H I S T S I M
A simulated histogram memory for regression tests.
All the counting error stuff is redirected to a regression counter; see
documentation there. This just adds data handling.
copyright: see file COPYRIGHT
Mark Koennecke, October 2006
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include "fortify.h"
#include "sics.h"
#include "countdriv.h"
#include "counter.h"
#include "stringdict.h"
#include "HistMem.h"
#include "HistDriv.i"
#include "histsim.h"
static int iSet = 0;
static HistInt iSetVal = 0;
static HistMode eHistMode;
/*--------------------------------------------------------------------------*/
static int RegressConfig(pHistDriver self, SConnection *pCon,
pStringDict pOption, SicsInterp *pSics)
{
int i, iLength = 1, status;
char pData[132];
float fFail;
pCounterDriver count;
count = (pCounterDriver)self->pPriv;
if(eHistMode == eHTOF)
{
for(i = 0; i < self->data->rank; i++)
{
iLength *= self->data->iDim[i];
}
iLength *= self->data->nTimeChan;
}
/*
deal with error settings
*/
status = StringDictGet(pOption,"errortype",pData,131);
if(status)
{
fFail = atof(pData);
count->Set(count,"errortype",1,fFail);
}
status = StringDictGet(pOption,"recover",pData,131);
if(status)
{
fFail = atof(pData);
count->Set(count,"recover",1,fFail);
}
status = StringDictGet(pOption,"finish",pData,131);
if(status)
{
fFail = atof(pData);
count->Set(count,"finish",1,fFail);
}
/*
configured test value
*/
status = StringDictGet(pOption,"testval",pData,131);
if(status)
{
iSet = 1;
iSetVal = atoi(pData);
}
return 1;
}
/*-------------------------------------------------------------------------*/
static int RegressStart(pHistDriver self, SConnection *pCon)
{
pCounterDriver pDriv;
pDriv = (pCounterDriver)self->pPriv;
pDriv->fPreset = self->fCountPreset;
pDriv->eMode = self->eCount;
return pDriv->Start(pDriv);
}
/*-------------------------------------------------------------------------*/
static int RegressPause(pHistDriver self, SConnection *pCon)
{
pCounterDriver pDriv;
pDriv = (pCounterDriver)self->pPriv;
pDriv->fPreset = self->fCountPreset;
pDriv->eMode = self->eCount;
return pDriv->Pause(pDriv);
}
/*------------------------------------------------------------------------*/
static int RegressContinue(pHistDriver self, SConnection *pCon)
{
pCounterDriver pDriv;
pDriv = (pCounterDriver)self->pPriv;
pDriv->fPreset = self->fCountPreset;
pDriv->eMode = self->eCount;
return pDriv->Continue(pDriv);
}
/*-------------------------------------------------------------------------*/
static int RegressHalt(pHistDriver self)
{
pCounterDriver pDriv;
pDriv = (pCounterDriver)self->pPriv;
return pDriv->Halt(pDriv);
}
/*-------------------------------------------------------------------------*/
static int RegressGetCountStatus(pHistDriver self, SConnection *pCon)
{
pCounterDriver pDriv;
float fControl;
pDriv = (pCounterDriver)self->pPriv;
return pDriv->GetStatus(pDriv,&fControl);
}
/*-------------------------------------------------------------------------*/
static int RegressGetError(pHistDriver self, int *iCode, char *pError, int iLen)
{
pCounterDriver pDriv;
pDriv = (pCounterDriver)self->pPriv;
return pDriv->GetError(pDriv, iCode,pError,iLen);
}
/*-------------------------------------------------------------------------*/
static int RegressTryAndFixIt(pHistDriver self, int iCode)
{
pCounterDriver pDriv;
pDriv = (pCounterDriver)self->pPriv;
return pDriv->TryAndFixIt(pDriv, iCode);
}
/*--------------------------------------------------------------------------*/
static int RegressGetData(pHistDriver self, SConnection *pCon)
{
pCounterDriver pDriv;
pDriv = (pCounterDriver)self->pPriv;
return pDriv->ReadValues(pDriv);
}
/*--------------------------------------------------------------------------*/
static int RegressGetHistogram(pHistDriver self, SConnection *pCon,
int i, int iStart, int iEnd, HistInt *lData)
{
int ii;
if(i < 0)
{
SCWrite(pCon,"ERROR: histogram out of range",eError);
return 0;
}
if(iSet == 1)
{
for(ii = iStart; ii < iEnd; ii++)
{
lData[ii-iStart] = iSetVal;
}
}
else
{
for(ii = iStart; ii < iEnd; ii++)
{
lData[ii-iStart] = random();
}
}
return 1;
}
/*------------------------------------------------------------------------*/
static int RegressSetHistogram(pHistDriver self, SConnection *pCon,
int i, int iStart, int iEnd, HistInt *lData)
{
iSet = 1;
iSetVal = lData[0];
return 1;
}
/*-------------------------------------------------------------------------*/
static int RegressPreset(pHistDriver self, SConnection *pCon, HistInt iVal)
{
iSet = 1;
iSetVal = iVal;
return 1;
}
/*------------------------------------------------------------------------*/
static int RegressFreePrivate(pHistDriver self)
{
pCounterDriver pDriv;
pDriv = (pCounterDriver)self->pPriv;
DeleteCounterDriver(pDriv);
return 1;
}
/*------------------------------------------------------------------------*/
static long RegressGetMonitor(pHistDriver self, int i, SConnection *pCon)
{
pCounterDriver pDriv;
long lVal;
pDriv = (pCounterDriver)self->pPriv;
return pDriv->lCounts[i];
}
/*------------------------------------------------------------------------*/
static float RegressGetTime(pHistDriver self, SConnection *pCon)
{
pCounterDriver pDriv;
long lVal;
pDriv = (pCounterDriver)self->pPriv;
return pDriv->fTime;
}
/*-------------------------------------------------------------------------*/
pHistDriver CreateRegressHM(pStringDict pOpt)
{
pHistDriver pNew = NULL;
/* create the general driver */
pNew = CreateHistDriver(pOpt);
if(!pNew)
{
return NULL;
}
/* put a Regresscounter in */
pNew->pPriv = (void *)NewRegressCounter("HistoRegress");
if(!pNew->pPriv)
{
DeleteHistDriver(pNew);
return NULL;
}
/* configure all those functions */
pNew->Configure = RegressConfig;
pNew->Start = RegressStart;
pNew->Halt = RegressHalt;
pNew->GetCountStatus = RegressGetCountStatus;
pNew->GetError = RegressGetError;
pNew->TryAndFixIt = RegressTryAndFixIt;
pNew->GetData = RegressGetData;
pNew->GetHistogram = RegressGetHistogram;
pNew->SetHistogram = RegressSetHistogram;
pNew->GetMonitor = RegressGetMonitor;
pNew->GetTime = RegressGetTime;
pNew->Preset = RegressPreset;
pNew->FreePrivate = RegressFreePrivate;
pNew->Pause = RegressPause;
pNew->Continue = RegressContinue;
StringDictAddPair(pOpt,"errortype","0");
StringDictAddPair(pOpt,"recover","1");
StringDictAddPair(pOpt,"testval","0");
return pNew;
}

View File

@ -183,6 +183,13 @@
lData[ii-iStart] = iSetVal; lData[ii-iStart] = iSetVal;
} }
} }
else if(iSet == 2)
{
for(ii = iStart; ii < iEnd; ii++)
{
lData[ii-iStart] = self->data->localBuffer[ii];
}
}
else else
{ {
for(ii = iStart; ii < iEnd; ii++) for(ii = iStart; ii < iEnd; ii++)
@ -196,7 +203,7 @@
static int SimSetHistogram(pHistDriver self, SConnection *pCon, static int SimSetHistogram(pHistDriver self, SConnection *pCon,
int i, int iStart, int iEnd, HistInt *lData) int i, int iStart, int iEnd, HistInt *lData)
{ {
iSet = 1; iSet = 2;
iSetVal = lData[0]; iSetVal = lData[0];
return 1; return 1;
} }

81
hkl.c
View File

@ -61,7 +61,6 @@
fprintf(fd,"%s hm %d\n",name, self->iHM); fprintf(fd,"%s hm %d\n",name, self->iHM);
fprintf(fd,"%s scantolerance %f\n", name,self->scanTolerance); fprintf(fd,"%s scantolerance %f\n", name,self->scanTolerance);
fprintf(fd,"%s nb %d\n", name, self->iNOR); fprintf(fd,"%s nb %d\n", name, self->iNOR);
fprintf(fd,"%s phiom %d\n", name, self->iOMPHI);
return 1; return 1;
} }
@ -689,7 +688,7 @@ int hklInRange(void *data, float fSet[4], int mask[4])
fSet[0] = dTheta; fSet[0] = dTheta;
/* for omega check against the limits +- SCANBORDER in order to allow for /* for omega check against the limits +- SCANBORDER in order to allow for
a omega scan a omega scan.
*/ */
MotorGetPar(self->pOmega,"softlowerlim",&fLimit); MotorGetPar(self->pOmega,"softlowerlim",&fLimit);
if((float)fSet[1] < fLimit + self->scanTolerance){ if((float)fSet[1] < fLimit + self->scanTolerance){
@ -721,7 +720,7 @@ static int calculateBisecting(MATRIX z1, pHKL self, SConnection *pCon,
float fSet[4], double myPsi, int iRetry) float fSet[4], double myPsi, int iRetry)
{ {
double stt, om, chi, phi, psi, ompsi, chipsi, phipsi; double stt, om, chi, phi, psi, ompsi, chipsi, phipsi;
int i, test; int i, test, mask[4];
/* /*
just the plain angle calculation just the plain angle calculation
@ -731,16 +730,31 @@ static int calculateBisecting(MATRIX z1, pHKL self, SConnection *pCon,
return 0; return 0;
} }
fSet[0] = stt;
fSet[1] = om;
fSet[2] = chi;
fSet[3] = phi;
if(iRetry == 1) { if(iRetry == 1) {
rotatePsi(om,chi,phi,psi,&ompsi,&chipsi,&phipsi); rotatePsi(om,chi,phi,myPsi,&ompsi,&chipsi,&phipsi);
fSet[1] = ompsi; fSet[1] = ompsi;
fSet[2] = circlify(chipsi); fSet[2] = circlify(chipsi);
fSet[3] = circlify(phipsi); fSet[3] = circlify(phipsi);
return 1; return 1;
} else {
if(hklInRange(self,fSet, mask) == 1){
return 1;
} else {
if(tryOmegaTweak(self,z1, &stt, &om, &chi, &phi) == 1){
fSet[0] = stt;
fSet[1] = om;
fSet[2] = chi;
fSet[3] = phi;
return 1;
} else { } else {
return findAllowedBisecting(self->fLambda, z1, fSet, hklInRange,self); return findAllowedBisecting(self->fLambda, z1, fSet, hklInRange,self);
} }
}
}
} }
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static int calculateNormalBeam(MATRIX z1, pHKL self, SConnection *pCon, static int calculateNormalBeam(MATRIX z1, pHKL self, SConnection *pCon,
@ -780,7 +794,7 @@ static int calculateNormalBeam(MATRIX z1, pHKL self, SConnection *pCon,
status = z1mToNormalBeam(self->fLambda, z3, &gamma, &omnb, &nu); status = z1mToNormalBeam(self->fLambda, z3, &gamma, &omnb, &nu);
omnb += 180.; /* omnb += 180.; */
mat_free(z3); mat_free(z3);
if(status != 1) if(status != 1)
{ {
@ -788,9 +802,13 @@ static int calculateNormalBeam(MATRIX z1, pHKL self, SConnection *pCon,
} }
if(checkNormalBeam(omnb, &gamma, nu,fSet,pCon,self)){ if(checkNormalBeam(omnb, &gamma, nu,fSet,pCon,self)){
return 1; return 1;
} else {
if(checkNormalBeam(omnb + 360., &gamma, nu, fSet,pCon,self)){
return 1;
} else { } else {
return 0; return 0;
} }
}
} }
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
static int calculateNormalBeamOmega(MATRIX z1, pHKL self, static int calculateNormalBeamOmega(MATRIX z1, pHKL self,
@ -903,30 +921,6 @@ static int calculateNormalBeamOmega(MATRIX z1, pHKL self,
if(self->iNOR == 0) if(self->iNOR == 0)
{ {
status = calculateBisecting(z1,self,pCon,fSet, myPsi, iRetry); status = calculateBisecting(z1,self,pCon,fSet, myPsi, iRetry);
/*
* Betrand mode: wrap phi rotation into omega
*/
if(self->iOMPHI > 0) {
if(ABS(fSet[2] - .0) < .1 || ABS(fSet[2] - 180.) < .1){
fSet[1] -= fSet[3];
/*
fSet[1] = 360. - fSet[3];
*/
fSet[3] = .0;
if(fSet[1] < 0.){
fSet[1] += 360.;
}
if(fSet[1] > 360.0){
fSet[1] -= 360.;
}
} else {
snprintf(pBueffel,511,
"ERROR: for omphi mode chi must be 0 or 180, is %f",
fSet[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
}
} }
else if(self->iNOR == 1) else if(self->iNOR == 1)
{ {
@ -1414,8 +1408,8 @@ ente:
if(strcmp(argv[1],"list") == 0 ) if(strcmp(argv[1],"list") == 0 )
{ {
sprintf(pBueffel, sprintf(pBueffel,
"lambda = %f Normal Beam = %d PHIOM = %d Quadrant = %d HM = %d", "lambda = %f Normal Beam = %d Quadrant = %d HM = %d",
self->fLambda, self->iNOR, self->iOMPHI, self->fLambda, self->iNOR,
self->iQuad,self->iHM); self->iQuad,self->iHM);
SCWrite(pCon,pBueffel,eValue); SCWrite(pCon,pBueffel,eValue);
sprintf(pBueffel,"UB = { %f %f %f", sprintf(pBueffel,"UB = { %f %f %f",
@ -1654,29 +1648,6 @@ ente:
SCSendOK(pCon); SCSendOK(pCon);
return 1; return 1;
} }
/*------------- phi omega mode (to be removed) */
else if(strcmp(argv[1],"phiom") == 0)
{
if(argc < 3)
{
snprintf(pBueffel,511,"%s.phiom = %d",argv[0],self->iOMPHI);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
if(!SCMatchRights(pCon,usUser))
{
return 0;
}
if(!isNumeric(argv[2]))
{
sprintf(pBueffel,"ERROR: %s was not recognized as a number", argv[2]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
self->iOMPHI = atoi(argv[2]);
SCSendOK(pCon);
return 1;
}
/*------------- quadrant */ /*------------- quadrant */
else if(strcmp(argv[1],"quadrant") == 0) else if(strcmp(argv[1],"quadrant") == 0)
{ {

1
hkl.i
View File

@ -15,7 +15,6 @@
int iManual; int iManual;
double fLastHKL[5]; double fLastHKL[5];
int iNOR; int iNOR;
int iOMPHI;
int iQuad; int iQuad;
int iHM; int iHM;
pMotor pTheta; pMotor pTheta;

View File

@ -26,7 +26,6 @@ $\langle$hkldat {\footnotesize ?}$\rangle\equiv$
\mbox{}\verb@ int iManual;@\\ \mbox{}\verb@ int iManual;@\\
\mbox{}\verb@ double fLastHKL[5];@\\ \mbox{}\verb@ double fLastHKL[5];@\\
\mbox{}\verb@ int iNOR;@\\ \mbox{}\verb@ int iNOR;@\\
\mbox{}\verb@ int iOMPHI;@\\
\mbox{}\verb@ int iQuad;@\\ \mbox{}\verb@ int iQuad;@\\
\mbox{}\verb@ int iHM;@\\ \mbox{}\verb@ int iHM;@\\
\mbox{}\verb@ pMotor pTheta;@\\ \mbox{}\verb@ pMotor pTheta;@\\

1
hkl.w
View File

@ -21,7 +21,6 @@ The object uses the following object data structure:
int iManual; int iManual;
double fLastHKL[5]; double fLastHKL[5];
int iNOR; int iNOR;
int iOMPHI;
int iQuad; int iQuad;
int iHM; int iHM;
pMotor pTheta; pMotor pTheta;

View File

@ -310,7 +310,7 @@ int HMControlAction(SConnection *pCon, SicsInterp *pSics,
assert(self); assert(self);
if(argc < 4) if(argc < 4)
{ {
sprintf(pBueffel,"ERROR: Usage %s start preset mode", argv[0]); snprintf(pBueffel,131,"ERROR: Usage %s start preset mode", argv[0]);
SCWrite(pCon,pBueffel,eError); SCWrite(pCon,pBueffel,eError);
return 0; return 0;
} }

110
hmdata.c
View File

@ -5,11 +5,15 @@
copyright: see file COPYRIGHT copyright: see file COPYRIGHT
Mark Koennecke, January 2003 Mark Koennecke, January 2003
Added loading HM data from file, Mark Koennecke, November 2006
-------------------------------------------------------------------------*/ -------------------------------------------------------------------------*/
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <time.h> #include <time.h>
#include "splitter.h"
#include "fortify.h" #include "fortify.h"
#include "hmdata.h" #include "hmdata.h"
#include "HistMem.h" #include "HistMem.h"
@ -46,7 +50,7 @@ void clearHMData(pHMdata self){
size *= self->iDim[i]; size *= self->iDim[i];
} }
if(self->tofMode){ if(self->tofMode){
size *= self->nTimeChan; size *= getNoOfTimebins(self);
} }
memset(self->localBuffer,0,size*sizeof(HistInt)); memset(self->localBuffer,0,size*sizeof(HistInt));
} }
@ -60,7 +64,7 @@ static int resizeBuffer(pHMdata self){
size *= self->iDim[i]; size *= self->iDim[i];
} }
if(self->tofMode){ if(self->tofMode){
size *= self->nTimeChan; size *= getNoOfTimebins(self);
} }
if(self->localBuffer != NULL){ if(self->localBuffer != NULL){
free(self->localBuffer); free(self->localBuffer);
@ -80,6 +84,7 @@ int configureHMdata(pHMdata self, pStringDict pOpt,
int status, i; int status, i;
float fVal; float fVal;
char pValue[80]; char pValue[80];
pHistMem master = NULL;
if(self->nTimeChan > 2) { if(self->nTimeChan > 2) {
self->tofMode = 1; self->tofMode = 1;
@ -111,6 +116,18 @@ int configureHMdata(pHMdata self, pStringDict pOpt,
self->updateIntervall = (int)rint(fVal); self->updateIntervall = (int)rint(fVal);
} }
status = StringDictGet(pOpt,"timeslave",pValue, 79);
if(status == 1) {
master = (pHistMem)FindCommandData(pServ->pSics,pValue,"HistMem");
if(master == NULL){
SCWrite(pCon,"ERROR: timeslave requested, but master HM not found",
eError);
} else {
self->timeslave = master->pDriv->data;
self->tofMode = 1;
}
}
/* /*
invalidate buffer invalidate buffer
*/ */
@ -138,7 +155,7 @@ int configureHMdata(pHMdata self, pStringDict pOpt,
int genTimeBinning(pHMdata self, float start, float step, int noSteps){ int genTimeBinning(pHMdata self, float start, float step, int noSteps){
int i; int i;
if(noSteps >= MAXCHAN){ if(noSteps >= MAXCHAN || self->timeslave != NULL){
return 0; return 0;
} }
for(i = 0; i < noSteps; i++){ for(i = 0; i < noSteps; i++){
@ -150,6 +167,10 @@ int genTimeBinning(pHMdata self, float start, float step, int noSteps){
} }
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
int setTimeBin(pHMdata self, int index, float value){ int setTimeBin(pHMdata self, int index, float value){
if(self->timeslave != NULL){
return 0;
}
if(index >= 0 && index < MAXCHAN){ if(index >= 0 && index < MAXCHAN){
self->timeBinning[index] = value; self->timeBinning[index] = value;
} else { } else {
@ -157,7 +178,7 @@ int setTimeBin(pHMdata self, int index, float value){
} }
self->tofMode = 1; self->tofMode = 1;
if(index > self->nTimeChan){ if(index > self->nTimeChan){
self->nTimeChan = index; self->nTimeChan = index+1;
return resizeBuffer(self); return resizeBuffer(self);
} }
return 1; return 1;
@ -168,17 +189,27 @@ int isInTOFMode(pHMdata self){
} }
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
int getNoOfTimebins(pHMdata self){ int getNoOfTimebins(pHMdata self){
if(self->timeslave != NULL){
return getNoOfTimebins(self->timeslave);
} else {
return self->nTimeChan; return self->nTimeChan;
}
} }
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
float *getTimeBinning(pHMdata self){ float *getTimeBinning(pHMdata self){
if(self->timeslave != NULL){
return getTimeBinning(self->timeslave);
} else {
return self->timeBinning; return self->timeBinning;
}
} }
/*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/
void clearTimeBinning(pHMdata self){ void clearTimeBinning(pHMdata self){
if(self->timeslave == NULL){
self->nTimeChan = 1; self->nTimeChan = 1;
self->tofMode = 0; self->tofMode = 0;
resizeBuffer(self); resizeBuffer(self);
}
} }
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
void getHMDataDim(pHMdata self, int iDim[MAXDIM], int *rank){ void getHMDataDim(pHMdata self, int iDim[MAXDIM], int *rank){
@ -193,7 +224,7 @@ long getHMDataLength(pHMdata self){
length *= self->iDim[i]; length *= self->iDim[i];
} }
if(self->tofMode){ if(self->tofMode){
length *= self->nTimeChan; length *= getNoOfTimebins(self);
} }
return length; return length;
} }
@ -227,6 +258,10 @@ static int updateHMbuffer(pHistMem hist, int bank, SConnection *pCon){
assert(self); assert(self);
if(self->timeslave != NULL){
resizeBuffer(self);
}
for(i = 0; i < 3; i++){ for(i = 0; i < 3; i++){
status = hist->pDriv->GetHistogram(hist->pDriv,pCon, status = hist->pDriv->GetHistogram(hist->pDriv,pCon,
bank,0,getHMDataLength(self), bank,0,getHMDataLength(self),
@ -292,7 +327,7 @@ HistInt *getHMDataBufferPointer(pHistMem hist,SConnection *pCon){
assert(self); assert(self);
if(self->localBuffer == NULL){ if(self->localBuffer == NULL || self->timeslave != NULL){
resizeBuffer(self); resizeBuffer(self);
} }
/* /*
@ -327,7 +362,7 @@ long sumHMDataRectangle(pHistMem hist, SConnection *pCon,
int iStart[MAXDIM], int iEnd[MAXDIM]) { int iStart[MAXDIM], int iEnd[MAXDIM]) {
HistInt *iData; HistInt *iData;
pHMdata self = hist->pDriv->data; pHMdata self = hist->pDriv->data;
int i, iHistLength, status, iIndex; int i, iHistLength, status, iIndex, myrank;
char pBueffel[256]; char pBueffel[256];
unsigned long lSum, lRowSum; unsigned long lSum, lRowSum;
@ -336,7 +371,12 @@ long sumHMDataRectangle(pHistMem hist, SConnection *pCon,
/* /*
error checking error checking
*/ */
for(i = 0; i < self->rank; i++){ myrank = self->rank;
if(isInTOFMode(self)){
self->iDim[self->rank] = getNoOfTimebins(self);
myrank++;
}
for(i = 0; i < myrank; i++){
if( (iStart[i] < 0) || (iStart[i] > self->iDim[i]) ) { if( (iStart[i] < 0) || (iStart[i] > self->iDim[i]) ) {
sprintf(pBueffel,"ERROR: %d is out of data dimension range", sprintf(pBueffel,"ERROR: %d is out of data dimension range",
iStart[i]); iStart[i]);
@ -367,13 +407,14 @@ long sumHMDataRectangle(pHistMem hist, SConnection *pCon,
iHistLength = getHMDataLength(self); iHistLength = getHMDataLength(self);
/* actually sum */ /* actually sum */
switch(self->rank) switch(myrank)
{ {
case 1: case 1:
lSum = SumRow(self->localBuffer, iHistLength, lSum = SumRow(self->localBuffer, iHistLength,
iStart[0], iEnd[0]); iStart[0], iEnd[0]);
break; break;
case 2: case 2:
if(isInTOFMode(self)){
lSum = 0; lSum = 0;
for(i = iStart[0]; i < iEnd[0]; i++){ for(i = iStart[0]; i < iEnd[0]; i++){
iIndex = i*self->iDim[1]; iIndex = i*self->iDim[1];
@ -381,11 +422,20 @@ long sumHMDataRectangle(pHistMem hist, SConnection *pCon,
iIndex+iStart[1], iIndex+iEnd[1]); iIndex+iStart[1], iIndex+iEnd[1]);
lSum += lRowSum; lSum += lRowSum;
} }
} else {
lSum = 0;
for(i = iStart[1]; i < iEnd[1]; i++){
iIndex = i*self->iDim[0];
lRowSum = SumRow(self->localBuffer,iHistLength,
iIndex+iStart[0], iIndex+iEnd[0]);
lSum += lRowSum;
}
}
break; break;
default: default:
sprintf(pBueffel, sprintf(pBueffel,
"ERROR: summing in %d dimensions not yet implemented", "ERROR: summing in %d dimensions not yet implemented",
self->rank); myrank);
SCWrite(pCon,pBueffel,eError); SCWrite(pCon,pBueffel,eError);
return -1; return -1;
break; break;
@ -395,3 +445,43 @@ long sumHMDataRectangle(pHistMem hist, SConnection *pCon,
} }
return lSum; return lSum;
} }
/*--------------------------------------------------------------------------*/
int loadHMData(pHMdata self, SConnection *pCon, char *filename){
FILE *fd = NULL;
char buffer[1024], pNumber[80], *pPtr;
long i = 0, length;
HistInt *data = NULL;
fd = fopen(filename,"r");
if(fd == NULL){
snprintf(buffer,1023,"ERROR: failed to open file %s", filename);
SCWrite(pCon,buffer,eError);
return 0;
}
length = getHMDataLength(self);
if(self->localBuffer == NULL || self->timeslave != NULL){
resizeBuffer(self);
}
data = self->localBuffer;
if(data == NULL){
SCWrite(pCon,"ERROR: failed to allocate HM", eError);
fclose(fd);
return 0;
}
while(i < length && fgets(buffer,1024,fd) != NULL){
pPtr = buffer;
while(pPtr != NULL){
pPtr = sicsNextNumber(pPtr,pNumber);
if(pPtr != NULL){
data[i] = atoi(pNumber);
i++;
}
}
}
if(i < length-1){
SCWrite(pCon,"WARNING: not enough data in file to fill HM",eWarning);
}
fclose(fd);
return 1;
}

View File

@ -16,7 +16,7 @@
#define MAXDIM 3 #define MAXDIM 3
typedef struct { typedef struct __hmdata{
int rank; int rank;
int iDim[MAXDIM]; int iDim[MAXDIM];
int nTimeChan; int nTimeChan;
@ -26,6 +26,7 @@
int updateIntervall; int updateIntervall;
int updateFlag; int updateFlag;
HistInt *localBuffer; HistInt *localBuffer;
struct __hmdata *timeslave;
} HMdata, *pHMdata; } HMdata, *pHMdata;
@ -56,6 +57,7 @@
long sumHMDataRectangle(pHistMem self, SConnection *pCon, long sumHMDataRectangle(pHistMem self, SConnection *pCon,
int start[MAXDIM], int end[MAXDIM]); int start[MAXDIM], int end[MAXDIM]);
int loadHMData(pHMdata self, SConnection *pCon, char *filename);
#endif #endif

View File

@ -11,7 +11,7 @@ display clients gone mad. This task is also handled through this class.
In order to do this, the following data structure is needed: In order to do this, the following data structure is needed:
@d hmdatadat @{ @d hmdatadat @{
typedef struct { typedef struct __hmdata{
int rank; int rank;
int iDim[MAXDIM]; int iDim[MAXDIM];
int nTimeChan; int nTimeChan;
@ -21,6 +21,7 @@ In order to do this, the following data structure is needed:
int updateIntervall; int updateIntervall;
int updateFlag; int updateFlag;
HistInt *localBuffer; HistInt *localBuffer;
struct __hmdata *timeslave;
} HMdata, *pHMdata; } HMdata, *pHMdata;
@} @}
@ -52,6 +53,7 @@ The following functions work on this data structure:
long sumHMDataRectangle(pHistMem self, SConnection *pCon, long sumHMDataRectangle(pHistMem self, SConnection *pCon,
int start[MAXDIM], int end[MAXDIM]); int start[MAXDIM], int end[MAXDIM]);
int loadHMData(pHMdata self, SConnection *pCon, char *filename);
@} @}
\begin{description} \begin{description}
@ -83,6 +85,8 @@ the histogram memory and not from the buffer the next time round.
pointer of HMdata. Use with extra care! pointer of HMdata. Use with extra care!
\item[sumHMDataRectangle] sums a rectangular box delimted by start and end \item[sumHMDataRectangle] sums a rectangular box delimted by start and end
from the histogram memory. from the histogram memory.
\item[loadHMData] loads histogram memory data from a file. This is for
debugging purposes. The file must contain enough numbers to fill the HM.
\end{description} \end{description}

View File

@ -12,8 +12,9 @@ Markus Zolliker, March 2005
typedef struct Item { typedef struct Item {
struct Item *next; struct Item *next;
const char *type; char *type;
const char *name; char *name;
char *desc;
Initializer maker; Initializer maker;
int startupOnly; int startupOnly;
} Item; } Item;
@ -21,15 +22,17 @@ typedef struct Item {
static Item *list = NULL; static Item *list = NULL;
static int startup = 1; static int startup = 1;
void MakeInitializer(const char *type, const char *name, Initializer maker, int startupOnly) { void MakeInitializer(const char *type, const char *name, Initializer maker,
int startupOnly, const char *desc) {
Item *item; Item *item;
item = calloc(1, sizeof *item); item = calloc(1, sizeof *item);
assert(item); assert(item);
item->maker = maker; item->maker = maker;
item->next = list; item->next = list;
item->type = type; item->type = strdup(type);
item->name = name; item->name = strdup(name);
item->desc = strdup(desc);
item->startupOnly = startupOnly; item->startupOnly = startupOnly;
list = item; list = item;
} }
@ -84,6 +87,40 @@ static int MakeObject(SConnection *con, SicsInterp *sics,
} }
} }
static int DriverList(SConnection *con, SicsInterp *sics,
void *data, int argc, char *argv[]) {
Item *p;
char *name, *type;
if (argc < 2 || strcasecmp(argv[1], "list") == 0) {
for (p = list; p != NULL; p = p->next) {
if (argc < 3) {
SCPrintf(con, eStatus, "%s %s %s", p->type, p->name, p->desc);
} else if (strcasecmp(argv[2], p->type) == 0) {
SCPrintf(con, eStatus, "%s %s", p->name, p->desc);
}
}
} else {
if (argc == 2) {
name = argv[1];
type = "Object";
} else {
name = argv[2];
type = argv[1];
}
p = list;
while (p != NULL && (strcasecmp(p->type, type) != 0 || strcasecmp(p->name, name) != 0)) {
p = p->next;
}
if (p) {
SCPrintf(con, eValue, "%s", p->desc);
} else {
SCPrintf(con, eValue, "notfound");
}
}
return 1;
}
static int RemoveObject(SConnection *con, SicsInterp *sics, static int RemoveObject(SConnection *con, SicsInterp *sics,
void *data, int argc, char *argv[]) { void *data, int argc, char *argv[]) {
CmdInitializer cmdin; CmdInitializer cmdin;
@ -91,7 +128,7 @@ static int RemoveObject(SConnection *con, SicsInterp *sics,
char *className; char *className;
if (argc != 2) { if (argc != 2) {
SCPrintf(con, eError, "%s has 1 argument", argv[0]); SCPrintf(con, eError, "%s needs 1 argument", argv[0]);
return 0; return 0;
} }
@ -124,16 +161,20 @@ static void KillInitializers(void *data) {
item = list; item = list;
while (item) { while (item) {
next = item->next; next = item->next;
if (item->name) free(item->name);
if (item->type) free(item->type);
if (item->desc) free(item->desc);
free(item); free(item);
item = next; item = next;
} }
list = NULL; list = NULL;
} }
void MakeDriver(const char *driver, CmdInitializer maker, int startupOnly) { void MakeDriver(const char *driver, CmdInitializer maker, int startupOnly, const char *desc) {
if (! FindCommand(pServ->pSics, "MakeObject")) { if (! FindCommand(pServ->pSics, "MakeObject")) {
AddCommandWithFlag(pServ->pSics, "MakeObject", MakeObject, KillInitializers, NULL, 0); AddCommandWithFlag(pServ->pSics, "MakeObject", MakeObject, KillInitializers, NULL, 0);
AddCommandWithFlag(pServ->pSics, "RemoveObject", RemoveObject, NULL, NULL, 0); AddCommandWithFlag(pServ->pSics, "RemoveObject", RemoveObject, NULL, NULL, 0);
AddCommandWithFlag(pServ->pSics, "DriverList", DriverList, NULL, NULL, 0);
} }
MakeInitializer("Object", driver, (Initializer)maker, startupOnly); MakeInitializer("Object", driver, (Initializer)maker, startupOnly, desc);
} }

View File

@ -12,7 +12,8 @@ Markus Zolliker, March 2005
typedef void (*Initializer)(void); typedef void (*Initializer)(void);
void MakeInitializer(const char *type, const char *name, Initializer maker, int startupOnly); void MakeInitializer(const char *type, const char *name, Initializer maker, int startupOnly,
const char *desc);
/* /*
install an initializer install an initializer
@ -54,7 +55,8 @@ typedef int (*CmdInitializer) (SConnection *pCon, int argc, char *argv[], int dy
- dynamic: the initializer was called _after_ startup - dynamic: the initializer was called _after_ startup
*/ */
void MakeDriver(const char *driver, CmdInitializer maker, int startupOnly); void MakeDriver(const char *driver, CmdInitializer maker, int startupOnly,
const char *desc);
/* /*
Install a driver of type "Object" with the initializer function maker. Install a driver of type "Object" with the initializer function maker.
- startupOnly: the driver creation should only be possible at startup - startupOnly: the driver creation should only be possible at startup

View File

@ -34,7 +34,7 @@
/*-------------------------- conversion routines -------------------------*/ /*-------------------------- conversion routines -------------------------*/
static float ang2x(pLin2Ang self, float fAngle) static float ang2x(pLin2Ang self, float fAngle)
{ {
return self->length*sin((fAngle+self->zero)/RD); return self->length*tan((fAngle+self->zero)/RD);
} }
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static float x2ang(pLin2Ang self, float fX) static float x2ang(pLin2Ang self, float fX)
@ -44,7 +44,7 @@
assert(self->length > 0.); assert(self->length > 0.);
dt = fX/self->length; dt = fX/self->length;
return RD*asin(dt) - self->zero; return RD*atan(dt) - self->zero;
} }
/*============== functions in the interface ============================*/ /*============== functions in the interface ============================*/
static void *Lin2AngGetInterface(void *pData, int iID) static void *Lin2AngGetInterface(void *pData, int iID)

View File

@ -9,4 +9,4 @@
MFLAGS=-f makefile_linux$(DUMMY) MFLAGS=-f makefile_linux$(DUMMY)
HDFROOT=/afs/psi.ch/project/sinq/sl-linux HDFROOT=/usr/local

132
macro.c
View File

@ -2,7 +2,7 @@
All you need to evaluate macros with SICS All you need to evaluate macros with SICS
The implmentation for the macro stuff is complex and non intuitive. The implementation for the macro stuff is complex and non intuitive.
This is the price to pay for adding the extremly powerful and This is the price to pay for adding the extremly powerful and
strong Tcl-interpreter to SICS. The problem is that Tcl does not strong Tcl-interpreter to SICS. The problem is that Tcl does not
know anything about connections and our error handling. We have know anything about connections and our error handling. We have
@ -770,6 +770,127 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp,
} }
return 1; return 1;
} }
/*-----------------------------------------------------------------------*/
int GumPut(SConnection *pCon, SicsInterp *pInter, void *pData,
int argc, char *argv[])
{
OutCode eOut = eWarning;
int i = 0, iCode, iLen;
int iMacro;
char *ppCode;
char *pMessage = NULL;
commandContext cc;
assert(pCon);
assert(pInter);
if(argc < 2)
{
SCWrite(pCon,"Insufficient arguments to ClientPut",eError);
return 0;
}
/* handle optional I/O codes */
if(argc > 2)
{
/* the last one must be the code */
iCode = argc - 1;
ppCode = strdup(argv[iCode]);
strtolower(ppCode);
while(pCode[i] != NULL)
{
if(strcmp(pCode[i],ppCode) == 0)
{
break;
}
i++;
}
if(ppCode)
{
free(ppCode);
}
}
else
{
i = 10;
iCode = argc;
}
switch(i)
{
case 0:
eOut = eInternal;
break;
case 1:
eOut = eCommand;
break;
case 2:
eOut = eHWError;
break;
case 3:
eOut = eInError;
break;
case 4:
eOut = eStatus;
break;
case 5:
eOut = eValue;
break;
case 6:
eOut = eWarning;
break;
case 7:
eOut = eFinish;
break;
case 8:
eOut = eEvent;
break;
case 9:
eOut = eWarning;
break;
case 10:
eOut = eError;
break;
default:
eOut = eWarning;
iCode = argc;
break;
}
/* recombine the message */
/* find length */
iLen = 0;
for(i = 1; i < iCode; i++)
{
iLen += strlen(argv[i]);
}
pMessage = (char *)malloc((iLen+100)*sizeof(char));
if(!pMessage)
{
SCWrite(pCon,"ERROR: out of memory in clientput",eError);
return 0;
}
memset(pMessage,0,(iLen+100)*sizeof(char));
Arg2Text(iCode-1,&argv[1],pMessage,(iLen+100)*sizeof(char));
/* now write, thereby tunneling macro flag in order to get proper
write to client and not into interpreter. We also make sure that the device
is gumput
*/
iMacro = SCinMacro(pCon);
SCsetMacro(pCon,0);
cc = SCGetContext(pCon);
strcpy(cc.deviceID,"gumput");
SCPushContext2(pCon,cc);
SCWrite(pCon,pMessage,eOut);
SCPopContext(pCon);
SCsetMacro(pCon,iMacro);
if(pMessage)
{
free(pMessage);
}
return 1;
}
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
int Broadcast(SConnection *pCon, SicsInterp *pInter, void *pData, int Broadcast(SConnection *pCon, SicsInterp *pInter, void *pData,
int argc, char *argv[]) int argc, char *argv[])
@ -891,14 +1012,9 @@ static int ProtectedExec(ClientData clientData, Tcl_Interp *interp,
if (pCommand != pBueffel) free(pCommand); if (pCommand != pBueffel) free(pCommand);
if(iRet == TCL_OK) if(iRet == TCL_OK)
{ {
/* we do not now why, but at some time it was found that if(strlen(pTcl->result) > 0){
we need a copy, and can not use pTcl->result directly
SCWrite(pCon,pTcl->result,eStatus);
let us use SCPrintf, which maked always a copy
*/
SCPrintf(pCon, eStatus, "%s", pTcl->result); SCPrintf(pCon, eStatus, "%s", pTcl->result);
}
return 1; return 1;
} }
else else

View File

@ -14,6 +14,7 @@
#ifndef SICSMACRO #ifndef SICSMACRO
#define SICSMACRO #define SICSMACRO
#include <tcl.h> #include <tcl.h>
#include "sics.h"
#include "SCinter.h" #include "SCinter.h"
Tcl_Interp *MacroInit(SicsInterp *pInter); Tcl_Interp *MacroInit(SicsInterp *pInter);
@ -30,6 +31,8 @@
int argc, char *argv[]); int argc, char *argv[]);
int ClientPut(SConnection *pCon, SicsInterp *pInter, void *pData, int ClientPut(SConnection *pCon, SicsInterp *pInter, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
int GumPut(SConnection *pCon, SicsInterp *pInter, void *pData,
int argc, char *argv[]);
int Broadcast(SConnection *pCon, SicsInterp *pInter, void *pData, int Broadcast(SConnection *pCon, SicsInterp *pInter, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
int TransactAction(SConnection *pCon, SicsInterp *pSics, void *pData, int TransactAction(SConnection *pCon, SicsInterp *pSics, void *pData,

View File

@ -30,14 +30,22 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \
s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) mcreader.o mccontrol.o\ s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) mcreader.o mccontrol.o\
hmdata.o nxscript.o tclintimpl.o sicsdata.o mcstascounter.o \ hmdata.o nxscript.o tclintimpl.o sicsdata.o mcstascounter.o \
mcstashm.o initializer.o remob.o tclmotdriv.o protocol.o \ mcstashm.o initializer.o remob.o tclmotdriv.o protocol.o \
sinfox.o sicslist.o cone.o hipadaba.o sicshipadaba.o statistics.o sinfox.o sicslist.o cone.o hipadaba.o sicshipadaba.o statistics.o \
moregress.o hdbcommand.o multicounter.o regresscter.o histregress.o \
sicshdbadapter.o polldriv.o sicspoll.o statemon.o
MOTOROBJ = motor.o simdriv.o MOTOROBJ = motor.o simdriv.o
COUNTEROBJ = countdriv.o simcter.o counter.o COUNTEROBJ = countdriv.o simcter.o counter.o
VELOOBJ = velo.o velosim.o VELOOBJ = velo.o velosim.o
.SUFFIXES: .SUFFIXES:
.SUFFIXES: .tcl .htm .c .o .SUFFIXES: .tcl .htm .c .o .tc
.tc.c:
tjxp $*.tc $*.c
#--- This .SECONDARY. target is necessary to preserve generated .c files for debugging
.SECONDARY.: sicspoll.c polldriv.c
all: libmat libhlib libtecsl libpsi SICServer all: libmat libhlib libtecsl libpsi SICServer

View File

@ -6,11 +6,11 @@
# Markus Zolliker, March 2003 # Markus Zolliker, March 2003
#========================================================================== #==========================================================================
# assign if the National Instrument GPIB driver is available # assign if the National Instrument GPIB driver is available
SINQDIR=/afs/psi.ch/project/sinq SINQDIR=/usr/local
NI= #NI=
#NI= -DHAVENI NI= -DHAVENI
#NIOBJ= nigpib.o NIOBJ= nigpib.o
#NILIB=$(SINQDIR)/linux/lib/cib.o NILIB=$(SINQDIR)/lib/cib.o
include linux_def include linux_def
@ -26,7 +26,7 @@ SUBLIBS = psi/libpsi.a psi/hardsup/libhlib.a matrix/libmatrix.a \
LIBS = -L$(HDFROOT)/lib $(SUBLIBS) $(NILIB)\ LIBS = -L$(HDFROOT)/lib $(SUBLIBS) $(NILIB)\
-ltcl8.4 -lmxml $(HDFROOT)/lib/libhdf5.a \ -ltcl8.4 -lmxml $(HDFROOT)/lib/libhdf5.a \
$(HDFROOT)/lib/libmfhdf.a $(HDFROOT)/lib/libdf.a \ $(HDFROOT)/lib/libmfhdf.a $(HDFROOT)/lib/libdf.a \
-ljpeg -ldl -lz -lm -lc -lmxml -lghttp -ljpeg -ljson -ldl -lz -lsz -lm -lc
include make_gen include make_gen

View File

@ -26,7 +26,7 @@ SUBLIBS = psi/libpsi.a psi/hardsup/libhlib.a matrix/libmatrix.a \
LIBS = -L$(HDFROOT)/lib $(SUBLIBS) $(NILIB)\ LIBS = -L$(HDFROOT)/lib $(SUBLIBS) $(NILIB)\
-ltcl8.3 $(HDFROOT)/lib/libhdf5.a \ -ltcl8.3 $(HDFROOT)/lib/libhdf5.a \
$(HDFROOT)/lib/libmfhdf.a $(HDFROOT)/lib/libdf.a \ $(HDFROOT)/lib/libmfhdf.a $(HDFROOT)/lib/libdf.a \
$(HDFROOT)/lib/libjpeg.a -lsz -ldl -lz -lmxml -lghttp -lm -lc $(HDFROOT)/lib/libjpeg.a -lsz -ljson -ldl -lz -lmxml -lghttp -lm -lc
include make_gen include make_gen

View File

@ -47,6 +47,7 @@
#include "counter.h" #include "counter.h"
#include "drive.h" #include "drive.h"
#include "maximize.h" #include "maximize.h"
#include "motor.h"
#define MAXPTS 100 #define MAXPTS 100
#define DEBUG 1 #define DEBUG 1
@ -55,6 +56,7 @@
pObjectDescriptor pDes; pObjectDescriptor pDes;
pCounter pCount; pCounter pCount;
int i360; int i360;
int maxpts;
}Maxxii; }Maxxii;
/*----------------------------------------------------------------------- /*-----------------------------------------------------------------------
@ -134,7 +136,25 @@
} }
return 1; return 1;
} }
/*----------------------------------------------------------------------*/
static float readMPDrivable(void *pVar, SConnection *pCon)
{
float value = -999.99;
pIDrivable pDriv = NULL;
pDummy pDum = (pDummy)pVar;
pDriv = GetDrivableInterface(pVar);
assert(pDriv != NULL);
if(strcmp(pDum->pDescriptor->name,"Motor") == 0)
{
MotorGetSoftPosition((pMotor)pVar,pCon,&value);
}
else
{
value = pDriv->GetValue(pVar,pCon);
}
return value;
}
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
int MaximizePeak(pMax self, void *pVar, char *pVarName, int MaximizePeak(pMax self, void *pVar, char *pVarName,
float fStep, CounterMode eMode, float fStep, CounterMode eMode,
@ -159,7 +179,7 @@
start: start:
lMax = 0; lMax = 0;
lMin = 0x7fffffff; lMin = 0x7fffffff;
fStart = pDriv->GetValue(pVar,pCon); fStart = readMPDrivable(pVar,pCon);
if(fStart < -999999.) if(fStart < -999999.)
{ {
return 0; return 0;
@ -167,16 +187,16 @@
/* search to the left until out of space or lCts < lMax/2. */ /* search to the left until out of space or lCts < lMax/2. */
SCWrite(pCon,"Searching for low angle boundary..",eWarning); SCWrite(pCon,"Searching for low angle boundary..",eWarning);
for(i = MAXPTS/2; i >= 0; i--) for(i = self->maxpts/2; i >= 0; i--)
{ {
/* drive motor */ /* drive motor */
fPos = fStart - (MAXPTS/2 - i)*fStep; fPos = fStart - (self->maxpts/2 - i)*fStep;
fPos = in360(self,fPos); fPos = in360(self,fPos);
if(maxDrive(pVar,pVarName,fPos,pCon) != 1) if(maxDrive(pVar,pVarName,fPos,pCon) != 1)
{ {
return 0; return 0;
} }
x[i] = pDriv->GetValue(pVar,pCon); x[i] = readMPDrivable(pVar,pCon);
/* count */ /* count */
if(maxCount(self->pCount,eMode,fPreset, &lCts,pCon) != 1) if(maxCount(self->pCount,eMode,fPreset, &lCts,pCon) != 1)
{ {
@ -218,7 +238,7 @@
goto start; goto start;
} }
/* no peak found or normal peak: continue at other side */ /* no peak found or normal peak: continue at other side */
if( (i < 1) || (y[MAXPTS/2] > lMax/2) ) if( (i < 1) || (y[self->maxpts/2] > lMax/2) )
{ {
iSkip = 0; iSkip = 0;
} }
@ -227,7 +247,7 @@
/* next case: all of the peak in measured half: /* next case: all of the peak in measured half:
find max value and skip the right half find max value and skip the right half
*/ */
for(i = MAXPTS/2; i > 0; i--) for(i = self->maxpts/2; i > 0; i--)
{ {
if(y[i] > lMax/2) if(y[i] > lMax/2)
{ {
@ -246,16 +266,16 @@
lMin = 100000; lMin = 100000;
lMax = -100000; lMax = -100000;
SCWrite(pCon,"Searching for high angle boundary..",eWarning); SCWrite(pCon,"Searching for high angle boundary..",eWarning);
for(i = MAXPTS/2; i < MAXPTS; i++) for(i = self->maxpts/2; i < self->maxpts; i++)
{ {
/* drive motor */ /* drive motor */
fPos = fStart + (i - MAXPTS/2) * fStep; fPos = fStart + (i - self->maxpts/2) * fStep;
fPos = in360(self,fPos); fPos = in360(self,fPos);
if(maxDrive(pVar,pVarName,fPos,pCon) != 1) if(maxDrive(pVar,pVarName,fPos,pCon) != 1)
{ {
return 0; return 0;
} }
x[i] = pDriv->GetValue(pVar,pCon); x[i] = readMPDrivable(pVar,pCon);
/* count */ /* count */
if(maxCount(self->pCount,eMode,fPreset, &lCts,pCon) != 1) if(maxCount(self->pCount,eMode,fPreset, &lCts,pCon) != 1)
{ {
@ -292,18 +312,18 @@
iTop = i; iTop = i;
iTop++; iTop++;
/* first case: peak is at high angle side */ /* first case: peak is at high angle side */
if( (i > MAXPTS-2) && (lMax*0.5 > lMin) ) if( (i > self->maxpts-2) && (lMax*0.5 > lMin) )
{ {
goto start; goto start;
} }
/* second case: no peak */ /* second case: no peak */
if( (iTop > MAXPTS-2) ) if( (iTop > self->maxpts-2) )
{ {
SCWrite(pCon,"ERROR: no peak found!",eError); SCWrite(pCon,"ERROR: no peak found!",eError);
return 0; return 0;
} }
/* third case: normal peak */ /* third case: normal peak */
if(y[MAXPTS/2] >= 0.5*lMax) if(y[self->maxpts/2] >= 0.5*lMax)
{ {
iTop--; iTop--;
} }
@ -313,7 +333,7 @@
*/ */
else else
{ {
for(i = MAXPTS/2; i < MAXPTS; i++) for(i = self->maxpts/2; i < self->maxpts; i++)
{ {
if(y[i] > lMax/2) if(y[i] > lMax/2)
{ {
@ -325,7 +345,7 @@
} }
} /* end of iSkip */ } /* end of iSkip */
if( (iBot < 2) || (iTop > MAXPTS-2) || (lMax < lMin*2) ) if( (iBot < 2) || (iTop > self->maxpts-2) || (lMax < lMin*2) )
{ {
SCWrite(pCon,"ERROR: no peak found!",eError); SCWrite(pCon,"ERROR: no peak found!",eError);
return 0; return 0;
@ -420,11 +440,14 @@
pNew->pDes = CreateDescriptor("Maximizer"); pNew->pDes = CreateDescriptor("Maximizer");
pNew->pCount = pCom->pData; pNew->pCount = pCom->pData;
pNew->i360 = 0; pNew->i360 = 0;
pNew->maxpts = 100;
AddCommand(pSics,"max",MaximizeAction,MaxKill,pNew); AddCommand(pSics,"max",MaximizeAction,MaxKill,pNew);
return 1; return 1;
} }
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------
* max motor step preset mode
* ---------------------------------------------------------------------*/
int MaximizeAction(SConnection *pCon, SicsInterp *pSics, void *pData, int MaximizeAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]) int argc, char *argv[])
{ {
@ -434,7 +457,7 @@
double dVal; double dVal;
float fStep, fPreset; float fStep, fPreset;
CounterMode eCount; CounterMode eCount;
int iRet; int iRet, iVal;
self = (pMax)pData; self = (pMax)pData;
assert(self); assert(self);
@ -446,9 +469,56 @@
return 1; return 1;
} }
/* enough arguments ?*/ /* enough arguments ?*/
if(argc < 5) if(argc < 5)
{ {
if(argc > 1)
{
strtolower(argv[1]);
if(strcmp(argv[1],"in360") == 0)
{
if(argc > 2)
{
iVal = atoi(argv[2]);
if(iVal != 0 && iVal != 1) {
SCWrite(pCon,"ERROR: only 0, 1 allowed for in360",eError);
return 0;
}
self->i360 = iVal;
SCSendOK(pCon);
return 1;
}
else
{
snprintf(pBueffel,255,"max.in360 = %d", self->i360);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
}
if(strcmp(argv[1],"maxpts") == 0)
{
if(argc > 2)
{
iVal = atoi(argv[2]);
if(iVal < 10 || iVal > 100) {
SCWrite(pCon,"ERROR: maxpst must be between 10 and 100",
eError);
return 0;
}
self->maxpts = iVal;
SCSendOK(pCon);
return 1;
}
else
{
snprintf(pBueffel,255,"max.maxpts = %d", self->maxpts);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
}
}
SCWrite(pCon,"ERROR: Insufficient number of arguments to max", SCWrite(pCon,"ERROR: Insufficient number of arguments to max",
eError); eError);
return 0; return 0;

36
mcstas/dmc/README Normal file
View File

@ -0,0 +1,36 @@
VIRTUAL DMC
This is the SICS-McStas virtual instrument DMC modelled after the real
powder diffcractometer DMC at SINQ:
http://sinq.web.psi.ch/sinq/instr/dmc/dmc.html
The McStas simulation used for this system has been verified against
the real instrument. The basic usage is to start the SICServer with:
./SICServer vdmc.tcl
in this directory. Then you can connect to SICS at localhost/2911
with any SICS client and start issuing commands.
In order to save simulation time, the simulation works with
neutron data files presimulated for four wavelength up to the sample.
This is why you get your wavelength coerced to the nearest
precalculated value.
If you desire to "measure" your own sample on virtual DMC, you first
have to create a LazyPulverix output file. You then can proceed to
load the sample into SICS with the SICS command:
sample load path-to-lazy-pulverix-outputfile
The command:
sample list
tells you which samples virtual DMC already knows about.
Questions and comments to: Mark.Koennecke@psi.ch

8454
mcstas/dmc/dmcafter.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@
# This is the scripted version using nxscript # This is the scripted version using nxscript
# #
# Mark Koennecke, May 2004 # Mark Koennecke, May 2004
# This is a special version for virtual DMC on lns00
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
proc storeMonochromator {} { proc storeMonochromator {} {
@ -75,14 +76,34 @@ proc makeLinks {} {
nxscript makelink dana dtnstep nxscript makelink dana dtnstep
nxscript makelink dana mlambda nxscript makelink dana mlambda
} }
#------------------------------------------------------------------------
proc makeSimFileName args {
global datahome
sicsdatanumber incr
set num [SplitReply [sicsdatanumber]]
return [makeSimForNum $num]
}
#------------------------------------------------------------------------
proc makeSimForNum {num} {
global datahome
set pre [string trim [SplitReply [sicsdataprefix]]]
set po [string trim [SplitReply [sicsdatapostfix]]]
return [format "%s/%s2006n%6.6d%s" $datahome $pre $num $po]
}
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# store DMC data # store DMC data
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
proc storedata {} { proc storedata {} {
global home global home wwwMode
if {$wwwMode == 1} {
set fil [makeSimFileName]
} else {
set fil [newFileName] set fil [newFileName]
}
lastdatafile $fil
clientput "Opening $fil for writing" clientput "Opening $fil for writing"
nxscript create4 $fil $home/dmc.dic nxscript createxml $fil $home/dmc.dic
writeStandardAttributes $fil writeStandardAttributes $fil
writeTextVar etitle title writeTextVar etitle title

View File

@ -1,13 +1,19 @@
# -------------------------------------------------------------------------- #--------------------------------------------------------------------------
# Initialization script for a virtual DMC instrument using a McStas # Initialization script for a virtual DMC instrument using a McStas
# simulationas a data source # simulationas a data source
# #
# Dr. Mark Koennecke, June 2005 # Dr. Mark Koennecke, June 2005
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# O P T I O N S # O P T I O N S
# wwwMode = 1 when running for the WWW-VDMC application
set wwwMode 0
set home $env(HOME)/src/workspace/sics/mcstas/dmc if {$wwwMode == 1} {
set home /home/lnswww/vinstrument/mcstas/dmc
set datahome /home/lnswww/www/vinstrument
} else {
set home $env(HOME)/psi/workspace/sics/mcstas/dmc
}
#--------------------------------- first all the server options are set #--------------------------------- first all the server options are set
#ServerOption RedirectFile $home/stdcdmc #ServerOption RedirectFile $home/stdcdmc
ServerOption ReadTimeOut 10 ServerOption ReadTimeOut 10
@ -120,18 +126,20 @@ SicsDataPrefix vdmc
#--------- make data number #--------- make data number
MakeDataNumber SicsDataNumber $home/DataNumber MakeDataNumber SicsDataNumber $home/DataNumber
VarMake SicsDataPostFix Text Internal VarMake SicsDataPostFix Text Internal
SicsDataPostFix ".hdf" SicsDataPostFix ".xml"
VarMake Adress Text User VarMake Adress Text User
VarMake phone Text User VarMake phone Text User
VarMake fax Text User VarMake fax Text User
VarMake email Text User VarMake email Text User
VarMake sample_mur Float User VarMake sample_mur Float User
VarMake lastdatafile Text User
#-------------------------------------------------------------------------- #--------------------------------------------------------------------------
# P R O C E D U R E S # P R O C E D U R E S
#-------------------------------------------------------------------------- #--------------------------------------------------------------------------
MakeDrive MakeDrive
MakeBatchManager MakeBatchManager
MakeNXScript MakeNXScript
MakeRuenBuffer
#-------------------- initialize scripted commands #-------------------- initialize scripted commands
source $home/vdmccom.tcl source $home/vdmccom.tcl
#-------------------- configure commandlog #-------------------- configure commandlog
@ -139,7 +147,6 @@ commandlog auto
commandlog intervall 5 commandlog intervall 5
#----------- enable sycamore #----------- enable sycamore
#InstallProtocolHandler
#InstallSinfox #InstallSinfox
#source sycFormat.tcl #source sycFormat.tcl
#source /usr/lib/tcllib1.6.1/stooop/stooop.tcl #source /usr/lib/tcllib1.6.1/stooop/stooop.tcl
@ -147,3 +154,95 @@ commandlog intervall 5
#source sinfo.tcl #source sinfo.tcl
#source sycamore.tcl #source sycamore.tcl
#Publish sinfo Spy #Publish sinfo Spy
#==================== install Hipadaba
proc hdbReadOnly {} {
error "Parameter is READ ONLY"
}
#------------------------------------
proc maketwotheta {} {
set txt [TwoThetaD]
set l [split $txt =]
set start [string trim [lindex $l 1]]
for {set i 0} {$i < 400} {incr i } {
append result [expr $start + $i * .2] " "
}
return $result
}
#-------------------------------------
InstallProtocolHandler
InstallHdb
MakeStateMon
hmake /dmc spy none
hsetprop /dmc 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
#------- SINQ
hmake /dmc/sinq spy none
hmakescript /dmc/sinq/proton_monitor "counter getmonitor 4" hdbReadOnly int
sicspoll /dmc/sinq/proton_monitor hdb 10
#-------- 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
#----------- 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
#---------- 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
#------------ 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
#---------------- 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

View File

@ -15,7 +15,9 @@ if { [info exists vdmcinit] == 0 } {
Publish copydmcdata User Publish copydmcdata User
Publish sample User Publish sample User
Publish wwwsics Spy Publish wwwsics Spy
Publish wwwfilefornumber Spy
mcinstall mcinstall
Publish gethm Spy
} }
source $home/log.tcl source $home/log.tcl
source $home/nxsupport.tcl source $home/nxsupport.tcl
@ -38,12 +40,19 @@ proc washlazy {name} {
if { [string first "H K L THETA 2THETA D VALUE" $line] > 0} { if { [string first "H K L THETA 2THETA D VALUE" $line] > 0} {
break break
} }
#-------- A second version to treat the messed up lazy pulverix files
# uploaded through the WWW-interface
if { [string first "H K L THETA" $line] >= 0} {
break
}
} }
#------- process data lines #------- process data lines
puts $out "// mult Q(hkl) F2 DW w" puts $out "// mult Q(hkl) F2 DW w"
clientput "HKL found at: $line"
while { [gets $in line] >= 0} { while { [gets $in line] >= 0} {
set num [scan $line "%d %d %d %f %f %f %f %f %d %d %d %f %f %f %f %f %d"\ set num [scan $line "%d %d %d %f %f %f %f %f %d %d %d %f %f %f %f %f %d"\
h k l th th2 d di sin h2 k2 l2 I F A B ang mul] h k l th th2 d di sin h2 k2 l2 I F A B ang mul]
clientput "Line = $num, $line"
if { $num == 17} { if { $num == 17} {
set q [expr (2.*3.14159265358979323846)/$d] set q [expr (2.*3.14159265358979323846)/$d]
set f2 [expr $F * $F] set f2 [expr $F * $F]
@ -155,6 +164,7 @@ proc rundmcoptsim {mode preset } {
} else { } else {
return $msg return $msg
} }
wait 5
} }
#------------------------------------------------------------------------ #------------------------------------------------------------------------
proc copydmcdataold { } { proc copydmcdataold { } {
@ -363,7 +373,7 @@ proc wwwpar {type mot} {
} }
#------------- wwwuser formats user information into a html table #------------- wwwuser formats user information into a html table
proc wwwuser {} { proc wwwuser {} {
lappend list title sample user email phone adress lappend list title user email phone adress
append txt "<table>" append txt "<table>"
foreach e $list { foreach e $list {
set ret [catch {$e} msg] set ret [catch {$e} msg]
@ -376,6 +386,14 @@ proc wwwuser {} {
} }
return $txt return $txt
} }
#------------- wwwfilefornumber returns the path to a data file for a
# number
proc wwwfilefornumber {num} {
return [makeSimForNum $num]
}
#-------------------------------------------------------------------
proc gethm {} {
banana uuget 0
}

View File

@ -33,6 +33,7 @@
#include "fourtable.h" #include "fourtable.h"
#include "lld.h" #include "lld.h"
#include "stdscan.h" #include "stdscan.h"
#include "exeman.h"
extern void SNXFormatTime(char *pBueffel, int iLen); extern void SNXFormatTime(char *pBueffel, int iLen);
extern float nintf(float f); extern float nintf(float f);
@ -445,7 +446,9 @@ static int MesureCalculateSettings(pMesure self, float fHKL[3], float fSet[4],
float fPsi, SConnection *pCon) float fPsi, SConnection *pCon)
{ {
int status, np; int status, np;
float step, tolerance; float step, tolerance, fHard;
char *scanvar = NULL;
char buffer[256];
SetHKLScanTolerance(self->pCryst,.0); SetHKLScanTolerance(self->pCryst,.0);
status = CalculateSettings(self->pCryst,fHKL,fPsi,0,fSet,pCon); status = CalculateSettings(self->pCryst,fHKL,fPsi,0,fSet,pCon);
@ -460,7 +463,26 @@ static int MesureCalculateSettings(pMesure self, float fHKL[3], float fSet[4],
np = getMesureNP(self,(double)fSet[0]); np = getMesureNP(self,(double)fSet[0]);
tolerance = (step * (float)np)/2. + .2; tolerance = (step * (float)np)/2. + .2;
SetHKLScanTolerance(self->pCryst,tolerance); SetHKLScanTolerance(self->pCryst,tolerance);
return CalculateSettings(self->pCryst,fHKL,fPsi,0,fSet,pCon); status = CalculateSettings(self->pCryst,fHKL,fPsi,0,fSet,pCon);
if(status != 1){
return status;
}
scanvar = GetFourCircleScanVar(self->stepTable,fSet[0]);
if(scanvar != NULL && strcmp(scanvar,"om") != 0){
tolerance *= 2.;
strcpy(buffer,"ERROR: 2theta limit problem:");
if(!MotorCheckBoundary(self->p2Theta,fSet[0]-tolerance,&fHard,
buffer,256-strlen(buffer))){
SCWrite(pCon,buffer,eWarning);
return 0;
}
if(!MotorCheckBoundary(self->p2Theta,fSet[0]+tolerance,&fHard,
buffer,256-strlen(buffer))){
SCWrite(pCon,buffer,eWarning);
return 0;
}
}
return status;
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
int MesureReflection(pMesure self, float fHKL[3], float fPsi, int MesureReflection(pMesure self, float fHKL[3], float fPsi,
@ -973,6 +995,8 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon)
int iRet, i,ii, iLF, iNP; int iRet, i,ii, iLF, iNP;
char pBueffel[512], pNum[10], pTime[132]; char pBueffel[512], pNum[10], pTime[132];
pEVControl pEva = NULL; pEVControl pEva = NULL;
pDummy pPtr = NULL;
pIDrivable pDriv = NULL;
assert(self); assert(self);
assert(pCon); assert(pCon);
@ -1058,7 +1082,20 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon)
fTemp = -777.77; fTemp = -777.77;
pEva = (pEVControl)FindCommandData(pServ->pSics,"temperature", pEva = (pEVControl)FindCommandData(pServ->pSics,"temperature",
"Environment Controller"); "Environment Controller");
if(pEva) if(pEva == NULL)
{
pPtr = (pDummy)FindCommandData(pServ->pSics,"temperature",
"RemObject");
if(pPtr != NULL)
{
pDriv = pPtr->pDescriptor->GetInterface(pPtr,DRIVEID);
if(pDriv != NULL)
{
fTemp = pDriv->GetValue(pPtr,pCon);
}
}
}
else
{ {
iRet = EVCGetPos(pEva, pCon,&fTemp); iRet = EVCGetPos(pEva, pCon,&fTemp);
} }
@ -1120,6 +1157,19 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon)
} }
return 1; return 1;
} }
/*---------------------------------------------------------------------*/
static FILE *openListFile(char *pName){
FILE *fd = NULL;
pDynString filename = NULL;
filename = findBatchFile(pServ->pSics,pName);
if(filename != NULL){
fd = fopen(GetCharArray(filename),"r");
DeleteDynString(filename);
} else {
fd = fopen(pName,"r");
}
return fd;
}
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
int MesureFile(pMesure self, char *pFile, int iSkip, SConnection *pCon) int MesureFile(pMesure self, char *pFile, int iSkip, SConnection *pCon)
{ {
@ -1132,7 +1182,7 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon)
assert(pCon); assert(pCon);
/* well before doing a thing, open the list file */ /* well before doing a thing, open the list file */
fd = fopen(pFile,"r"); fd = openListFile(pFile);
if(!fd) if(!fd)
{ {
sprintf(pBueffel,"ERROR: reflection file %s NOT found!",pFile); sprintf(pBueffel,"ERROR: reflection file %s NOT found!",pFile);
@ -1221,7 +1271,7 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon)
assert(pCon); assert(pCon);
/* well before doing a thing, open the list file */ /* well before doing a thing, open the list file */
fd = fopen(pFile,"r"); fd = openListFile(pFile);
if(!fd) if(!fd)
{ {
sprintf(pBueffel,"ERROR: reflection file %s NOT found!",pFile); sprintf(pBueffel,"ERROR: reflection file %s NOT found!",pFile);
@ -1280,7 +1330,7 @@ static int ScanReflection(pMesure self, float twoTheta, SConnection *pCon)
assert(pCon); assert(pCon);
/* well before doing a thing, open the list file */ /* well before doing a thing, open the list file */
fd = fopen(pFile,"r"); fd = openListFile(pFile);
if(!fd) if(!fd)
{ {
sprintf(pBueffel,"ERROR: reflection file %s NOT found!",pFile); sprintf(pBueffel,"ERROR: reflection file %s NOT found!",pFile);

View File

@ -73,5 +73,6 @@
/* ----------------------- Simulation -----------------------------------*/ /* ----------------------- Simulation -----------------------------------*/
MotorDriver *CreateSIM(SConnection *pCon, int argc, char *argv[]); MotorDriver *CreateSIM(SConnection *pCon, int argc, char *argv[]);
void KillSIM(void *pData); void KillSIM(void *pData);
MotorDriver *RGMakeMotorDriver(void);
#endif #endif

258
moregress.c Normal file
View File

@ -0,0 +1,258 @@
/**
* This is a regression testing motor driver for SICS.
* A parameter can be set which makes this driver cause
* various error conditions. This can then be used to
* verify and debug the working of upper level code
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, July 2007
*/
#include <stdlib.h>
#include <sics.h>
#include <modriv.h>
/*===================== supported errors ======================*/
#define NONE 0
#define STARTFAIL 1
#define BADPOS 2 /* positioning problem */
#define FAIL 3 /* failure */
#define OFFPOS 4 /* off pos by .2 */
#define READFAIL 5
#define RUN 6 /* keep running; for interrupt testing */
/*=============================================================*/
typedef struct __RGMoDriv{
/* general motor driver interface
fields. REQUIRED!
*/
float fUpper; /* upper limit */
float fLower; /* lower limit */
char *name;
int (*GetPosition)(void *self, float *fPos);
int (*RunTo)(void *self,float fNewVal);
int (*GetStatus)(void *self);
void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen);
int (*TryAndFixIt)(void *self, int iError,float fNew);
int (*Halt)(void *self);
int (*GetDriverPar)(void *self, char *name,
float *value);
int (*SetDriverPar)(void *self,SConnection *pCon,
char *name, float newValue);
void (*ListDriverPar)(void *self, char *motorName,
SConnection *pCon);
void (*KillPrivate)(void *self);
/* your drivers private fields follow below */
float target;
int errorType;
int recover;
int counter;
} RGMotorDriver;
/*================================================================
GetPos returns OKOK on success, HWFault on failure
------------------------------------------------------------------*/
static int RGGetPos(void *data, float *fPos){
RGMotorDriver *self = NULL;
self = (RGMotorDriver *)data;
if(self->errorType == READFAIL){
return HWFault;
}
if(self->errorType > 1 && self->errorType < 6){
*fPos = self->target - .2;
} else {
*fPos = self->target;
}
return OKOK;
}
/*----------------------------------------------------------------
RunTo starts the motor running. Returns OKOK on success, HWfault
on Errors
------------------------------------------------------------------*/
static int RGRunTo(void *data, float newValue){
RGMotorDriver *self = NULL;
self = (RGMotorDriver *)data;
self->target = newValue;
if(self->errorType == STARTFAIL){
return HWFault;
}
return OKOK;
}
/*-----------------------------------------------------------------
CheckStatus queries the sattus of a running motor. Possible return
values can be:
HWBusy : motor still running
HWFault : motor error detected
HWPosFault : motor finished, but position not reached
HWIdle : motor finished OK
HWWarn : motor issued warning
--------------------------------------------------------------------*/
static int RGCheckStatus(void *data){
RGMotorDriver *self = NULL;
self = (RGMotorDriver *)data;
switch(self->errorType){
case BADPOS:
return HWPosFault;
break;
case FAIL:
return HWFault;
break;
case RUN:
return HWBusy;
break;
}
return HWIdle;
}
/*------------------------------------------------------------------
GetError gets more information about error which occurred
*iCode is an integer error code to be used in TryFixIt as indicator
buffer is a buffer for a text description of the problem
iBufLen is the length of buffer
--------------------------------------------------------------------*/
static void RGGetError(void *data, int *iCode, char *buffer,
int iBufLen){
RGMotorDriver *self = NULL;
self = (RGMotorDriver *)data;
*iCode = self->errorType;
switch(self->errorType){
case NONE:
strncpy(buffer,"No error found",iBufLen);
break;
case BADPOS:
strncpy(buffer,"Position not reached",iBufLen);
break;
case FAIL:
strncpy(buffer,"Hardware is mad",iBufLen);
break;
case STARTFAIL:
strncpy(buffer,"Failed to start motor",iBufLen);
break;
case READFAIL:
strncpy(buffer,"Failed to read motor",iBufLen);
break;
}
}
/*------------------------------------------------------------------
TryAndFixIt tries everything which is possible in software to fix
a problem. iError is the error code from GetError, newValue is
the target value for the motor
Possible retrun values are:
MOTOK : everything fixed
MOTREDO : try again
MOTFAIL : cannot fix this
--------------------------------------------------------------------*/
static int RGFixIt(void *data, int iError, float newValue){
RGMotorDriver *self = NULL;
self = (RGMotorDriver *)data;
if(self->recover == 1){
self->errorType = NONE;
return MOTREDO;
}
return MOTFAIL;
}
/*-------------------------------------------------------------------
Halt tries to stop the motor. Halt errors are ignored
---------------------------------------------------------------------*/
static int RGHalt(void *data){
RGMotorDriver *self = NULL;
self = (RGMotorDriver *)data;
self->errorType = NONE;
return 1;
}
/*--------------------------------------------------------------------
GetDriverPar retrieves the value of a driver parameter.
Name is the name of the parameter, fValue the value when found.
Returns 0 on success, 0 else
-----------------------------------------------------------------------*/
static int RGGetDriverPar(void *data, char *name, float *value){
RGMotorDriver *self = NULL;
self = (RGMotorDriver *)data;
if(strcmp(name,"errortype") == 0){
*value = (float)self->errorType;
return 1;
} else if (strcmp(name,"recover") == 0){
*value = self->recover;
return 1;
}
return 0;
}
/*----------------------------------------------------------------------
SetDriverPar sets a driver parameter. Returns 0 on failure, 1 on
success. Name is the parameter name, pCon the connection to report
errors too, value the new value
------------------------------------------------------------------------*/
static int RGSetDriverPar(void *data, SConnection *pCon,
char *name, float value){
RGMotorDriver *self = NULL;
self = (RGMotorDriver *)data;
if(strcmp(name,"errortype") == 0){
self->errorType = (int)value;
return 1;
} else if (strcmp(name,"recover") == 0){
self->recover = (int)value;
return 1;
}
return 0;
}
/*-----------------------------------------------------------------------
ListDriverPar lists the names and values of driver parameters to
pCon. Motorname is the name of the motor ro prefix to the listing.
-------------------------------------------------------------------------*/
static void RGListDriverPar(void *data, char *motorname,
SConnection *pCon){
RGMotorDriver *self = NULL;
char buffer[256];
self = (RGMotorDriver *)data;
snprintf(buffer,255,"%s errortype = %d", motorname,
self->errorType);
SCWrite(pCon,buffer,eValue);
snprintf(buffer,255,"%s recover = %d", motorname,
self->recover);
SCWrite(pCon,buffer,eValue);
}
/*-----------------------------------------------------------------------
KillPrivate has the task to delete possibly dynamically allocated
memory in the private part of the driver structure
------------------------------------------------------------------------*/
static void RGKillPrivate(void *data){
RGMotorDriver *self = NULL;
self = (RGMotorDriver *)data;
}
/*=======================================================================*/
MotorDriver *RGMakeMotorDriver(void) {
RGMotorDriver *pNew = NULL;
pNew = malloc(sizeof(RGMotorDriver));
if(pNew == NULL){
return NULL;
}
memset(pNew,0,sizeof(RGMotorDriver));
pNew->GetPosition = RGGetPos;
pNew->RunTo = RGRunTo;
pNew->GetStatus = RGCheckStatus;
pNew->GetError = RGGetError;
pNew->TryAndFixIt = RGFixIt;
pNew->Halt = RGHalt;
pNew->GetDriverPar = RGGetDriverPar;
pNew->SetDriverPar = RGSetDriverPar;
pNew->ListDriverPar = RGListDriverPar;
pNew->KillPrivate = RGKillPrivate;
pNew->fLower = -180.;
pNew->fUpper = 180.;
return (MotorDriver *)pNew;
}

34
motor.c
View File

@ -76,13 +76,6 @@
#define IGNOREFAULT 10 #define IGNOREFAULT 10
#define MOVECOUNT 11 #define MOVECOUNT 11
/*------------------------------------------------------------------------
a tiny structure used in CallBack work
*/
typedef struct {
float fVal;
char *pName;
} MotCallback;
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static void *MotorGetInterface(void *pData, int iID) static void *MotorGetInterface(void *pData, int iID)
@ -416,7 +409,7 @@ static void handleMoveCallback(pMotor self, SConnection *pCon)
/* create and initialize parameters */ /* create and initialize parameters */
pM->ParArray = ObParCreate(12); pM->ParArray = ObParCreate(MOTOBPARLENGTH);
if(!pM->ParArray) if(!pM->ParArray)
{ {
free(pM); free(pM);
@ -606,6 +599,7 @@ extern void KillPiPiezo(void *pData);
if(iRet == 1) if(iRet == 1)
{ {
SCparChange(pCon); SCparChange(pCon);
InvokeCallBack(self->pCall,HDBVAL,self);
return iRet; return iRet;
} }
} }
@ -631,6 +625,7 @@ extern void KillPiPiezo(void *pData);
fLimit -= fChange; fLimit -= fChange;
ObParSet(self->ParArray,self->name,"softlowerlim",fLimit,pCon); ObParSet(self->ParArray,self->name,"softlowerlim",fLimit,pCon);
SCparChange(pCon); SCparChange(pCon);
InvokeCallBack(self->pCall,HDBVAL,self);
return 1; return 1;
} }
@ -652,6 +647,7 @@ extern void KillPiPiezo(void *pData);
ObParInit(self->ParArray,SZERO,"softzero",ZEROINACTIVE,usUser); ObParInit(self->ParArray,SZERO,"softzero",ZEROINACTIVE,usUser);
} }
} }
InvokeCallBack(self->pCall,HDBVAL,self);
SCparChange(pCon); SCparChange(pCon);
return iRet; return iRet;
@ -747,10 +743,11 @@ extern void KillPiPiezo(void *pData);
} }
/* check boundaries first */ /* check boundaries first */
iRet = MotorCheckBoundary(self,fNew,&fHard,pBueffel,511); iRet = MotorCheckBoundary(self,fNew,&fHard,pError,131);
if(!iRet) if(!iRet)
{ {
SCWrite(pCon,pBueffel,eStatus); snprintf(pBueffel,511,"ERROR: %s",pError);
SCWrite(pCon,pBueffel,eError);
SCSetInterrupt(pCon,eAbortOperation); SCSetInterrupt(pCon,eAbortOperation);
return 0; return 0;
} }
@ -784,6 +781,7 @@ extern void KillPiPiezo(void *pData);
self->retryCount = 0; self->retryCount = 0;
self->stopped = 0; self->stopped = 0;
self->fTarget = fHard; self->fTarget = fHard;
InvokeCallBack(self->pCall,HDBVAL,self);
self->posCount = 0; self->posCount = 0;
iRet = self->pDriver->RunTo(self->pDriver,fHard); iRet = self->pDriver->RunTo(self->pDriver,fHard);
if(iRet != OKOK) if(iRet != OKOK)
@ -1024,6 +1022,21 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray);
SCWrite(pCon,pBueffel,eError); SCWrite(pCon,pBueffel,eError);
return 0; return 0;
} }
} else if(strcmp(argv[2],"regress") == 0)
{
pDriver = RGMakeMotorDriver();
if(!pDriver)
{
return 0;
}
/* create the motor */
pNew = MotorInit("regress",argv[1],pDriver);
if(!pNew)
{
sprintf(pBueffel,"Failure to create motor %s",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
} }
else else
{ {
@ -1085,7 +1098,6 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray);
{ {
self->pDriver->ListDriverPar(self->pDriver,self->name, pCon); self->pDriver->ListDriverPar(self->pDriver,self->name, pCon);
} }
SCWrite(pCon,"ENDLIST",eFinish);
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
void MotorReset(pMotor pM) void MotorReset(pMotor pM)

View File

@ -14,6 +14,7 @@
#include "obdes.h" #include "obdes.h"
#include "interface.h" #include "interface.h"
#define MOTOBPARLENGTH 12
typedef struct __Motor { typedef struct __Motor {
pObjectDescriptor pDescriptor; pObjectDescriptor pDescriptor;
ObPar *ParArray; ObPar *ParArray;
@ -32,6 +33,13 @@
int stopped; int stopped;
} Motor; } Motor;
typedef Motor *pMotor; typedef Motor *pMotor;
/*------------------------------------------------------------------------
a tiny structure used in CallBack work
--------------------------------------------------------------------------*/
typedef struct {
float fVal;
char *pName;
} MotCallback;
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* parameter management */ /* parameter management */

429
multicounter.c Normal file
View File

@ -0,0 +1,429 @@
/**
* The MultiCounter is another counter which coordinates multiple
* counting objects, counters and histogram memories. It also calls a
* script function after TransferData which collects counters and monitors.
* The purpose is to have a flexible counter abstraction for upper level
* code such as maximizers and scan functions. The script can deal with
* counting on monitors or on sums of histogram memories.
*
* This is a bit unclean. The counter driver is of no use, therefore its
* private data structure is used to hold the other counters and the name
* of the script. It would have been better to inherit from counter but
* that would have required lost of type casts. I am to lazy for this.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, September 2006
*/
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include <tcl.h>
#include "multicounter.h"
#include "counter.h"
#include "HistMem.h"
#include "macro.h"
#include "splitter.h"
#define MAXSLAVE 16
#define NOCOUNTERS -2727
/*=============== code for the driver ======================================*/
typedef struct {
void *slaveData[MAXSLAVE];
pICountable slaves[MAXSLAVE];
char *transferScript;
int nSlaves;
}MultiCounter, *pMultiCounter;
/*--------------------------------------------------------------------------*/
static void KillMultiDriver(struct __COUNTER *data){
pMultiCounter self = (pMultiCounter)data->pData;
if(self == NULL){
return;
}
if(self->transferScript != NULL){
free(self->transferScript);
}
free(self);
}
/*============== countable interface functions ============================*/
static int MMCCHalt(void *pData){
int i, retVal = OKOK, status;
pCounter pCount = NULL;
pMultiCounter self = NULL;
pCount = (pCounter)pData;
if(pCount != NULL){
self = (pMultiCounter)pCount->pDriv->pData;
}
assert(self);
for(i = 0; i < self->nSlaves; i++){
status = self->slaves[i]->Halt(self->slaveData[i]);
if(status != OKOK)
retVal = status;
}
return retVal;
}
/*-------------------------------------------------------------------------*/
static int MMCCStart(void *pData, SConnection *pCon)
{
int i, status;
pCounter pCount = NULL;
pMultiCounter self = NULL;
pCount = (pCounter)pData;
if(pCount != NULL){
self = (pMultiCounter)pCount->pDriv->pData;
}
assert(self);
for(i = 0; i < self->nSlaves; i++){
self->slaves[i]->SetCountParameters(self->slaveData[i],
pCount->pDriv->fPreset, pCount->pDriv->eMode);
status = self->slaves[i]->StartCount(self->slaveData[i],pCon);
if(status != OKOK){
MMCCHalt(pData);
return status;
}
}
pCount->isUpToDate = 0;
pCount->tStart = time(NULL);
InvokeCallBack(pCount->pCall,COUNTSTART,pCon);
return OKOK;
}
/*-------------------------------------------------------------------------*/
static int MMCCStatus(void *pData, SConnection *pCon){
int status,i;
pCounter pCount = NULL;
pMultiCounter self = NULL;
pDummy pDum = NULL;
pCount = (pCounter)pData;
if(pCount != NULL){
self = (pMultiCounter)pCount->pDriv->pData;
}
assert(self);
if(self->nSlaves == 0) {
pCount->pDriv->iErrorCode = NOCOUNTERS;
return HWFault;
}
status = self->slaves[0]->CheckCountStatus(self->slaveData[0],pCon);
if(status == HWIdle || status == HWFault){
/*
stop counting on slaves when finished or when an error
occurred.
*/
InvokeCallBack(pCount->pCall,COUNTEND,pCon);
MMCCHalt(pCount);
}
for(i = 1; i < MAXSLAVE; i++){
if(self->slaves[i] != NULL){
pDum = (pDummy)self->slaveData[i];
if(strcmp(pDum->pDescriptor->name,"HistMem") == 0){
HistDirty((pHistMem)self->slaveData[i]);
}
}
}
return status;
}
/*-------------------------------------------------------------------------*/
static int MMCCPause(void *pData, SConnection *pCon){
int i, status;
pCounter pCount = NULL;
pMultiCounter self = NULL;
pCount = (pCounter)pData;
if(pCount != NULL){
self = (pMultiCounter)pCount->pDriv->pData;
}
assert(self);
for(i = 0; i < self->nSlaves; i++){
status = self->slaves[i]->Pause(self->slaveData[i],pCon);
if(status != OKOK){
MMCCHalt(pCount);
return status;
}
}
return OKOK;
}
/*--------------------------------------------------------------------------*/
static int MMCCContinue(void *pData, SConnection *pCon){
int i, status;
pCounter pCount = NULL;
pMultiCounter self = NULL;
pCount = (pCounter)pData;
if(pCount != NULL){
self = (pMultiCounter)pCount->pDriv->pData;
}
assert(self);
for(i = 0; i < self->nSlaves; i++){
status = self->slaves[i]->Continue(self->slaveData[i],pCon);
if(status != OKOK){
MMCCHalt(pCount);
return status;
}
}
return OKOK;
}
/*------------------------------------------------------------------------*/
static char *getNextMMCCNumber(char *pStart, char pNumber[80]){
int charCount = 0;
pNumber[0] = '\0';
/* advance to first digit */
while(isspace(*pStart) && *pStart != '\0'){
pStart++;
}
if(*pStart == '\0'){
return NULL;
}
/* copy */
while(!isspace(*pStart) && *pStart != '\0' && charCount < 78){
pNumber[charCount] = *pStart;
pStart++;
charCount++;
}
pNumber[charCount] = '\0';
return pStart;
}
/*-------------------------------------------------------------------------*/
static void loadCountData(pCounter pCount, const char *data){
char *pPtr = NULL;
char pNumber[80];
int i = 0;
pPtr = (char *)data;
pPtr = getNextMMCCNumber(pPtr,pNumber);
pCount->pDriv->fTime = atof(pNumber);
while(pPtr != NULL && i < MAXCOUNT){
pPtr = getNextMMCCNumber(pPtr,pNumber);
pCount->pDriv->lCounts[i] = atoi(pNumber);
i++;
}
}
/*--------------------------------------------------------------------------*/
static int MMCCTransfer(void *pData, SConnection *pCon){
int i, retVal = OKOK, status;
char pBueffel[132];
pCounter pCount = NULL;
pMultiCounter self = NULL;
int tclStatus;
pCount = (pCounter)pData;
if(pCount != NULL){
self = (pMultiCounter)pCount->pDriv->pData;
}
assert(self);
for(i = 0; i < self->nSlaves; i++){
status = self->slaves[i]->TransferData(self->slaveData[i], pCon);
if(status != OKOK){
retVal = status;
sprintf(pBueffel,"WARNING: slave histogram %d failed to transfer data",
i);
SCWrite(pCon,pBueffel,eWarning);
}
}
if(self->transferScript != NULL){
MacroPush(pCon);
tclStatus = Tcl_Eval(InterpGetTcl(pServ->pSics), self->transferScript);
if(tclStatus != TCL_OK){
snprintf(pBueffel,131,"ERROR: TransferScript returned: %s",
Tcl_GetStringResult(InterpGetTcl(pServ->pSics)));
SCWrite(pCon,pBueffel,eError);
MacroPop();
return HWFault;
}
MacroPop();
loadCountData(pCount,Tcl_GetStringResult(InterpGetTcl(pServ->pSics)));
}
return retVal;
}
/*-------------------------------------------------------------------------*/
static void MMCCParameter(void *pData, float fPreset, CounterMode eMode ){
int i;
pCounter pCount = NULL;
pMultiCounter self = NULL;
pCount = (pCounter)pData;
if(pCount != NULL){
self = (pMultiCounter)pCount->pDriv->pData;
}
assert(self);
for(i = 0; i < self->nSlaves; i++){
self->slaves[i]->SetCountParameters(self->slaveData[i], fPreset,
eMode);
}
}
/*======================= Driver Interface ==============================*/
static int MultiCounterSet(struct __COUNTER *self, char *name,
int iCter, float fVal){
return 0;
}
/*-----------------------------------------------------------------------*/
static int MultiCounterGet(struct __COUNTER *self, char *name,
int iCter, float *fVal){
return 0;
}
/*-----------------------------------------------------------------------*/
static int MultiCounterSend(struct __COUNTER *self, char *pText,
char *reply, int replylen){
strncpy(reply,"NOT Implemented",replylen);
return 0;
}
/*---------------------------------------------------------------------*/
static int MultiCounterError(struct __COUNTER *pData, int *iCode,
char *error, int errlen){
pCounter pCount = NULL;
pCount = (pCounter)pData;
if(pCount->pDriv->iErrorCode == NOCOUNTERS){
strncpy(error,"NO counters configured!",errlen);
} else {
strncpy(error,"Not Implemented", errlen);
}
return COTERM;
}
/*----------------------------------------------------------------------*/
static int MultiCounterFix(struct __COUNTER *self, int iCode){
return COTERM;
}
/*=============== Interpreter Interface ================================ */
int MultiCounterAction(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]){
pMultiCounter self = NULL;
pCounter pCount = NULL;
char buffer[256];
if(argc > 1){
strtolower(argv[1]);
if(strcmp(argv[1],"transferscript") == 0){
pCount = (pCounter)pData;
self = (pMultiCounter)pCount->pDriv->pData;
if(argc < 3){
SCPrintf(pCon,eValue,"%s.transferscript = %s",
argv[0],self->transferScript);
return 1;
} else {
if(!SCMatchRights(pCon,usUser)){
return 0;
}
if(self->transferScript != NULL){
free(self->transferScript);
}
Arg2Text(argc-2,&argv[2],buffer,255);
self->transferScript = strdup(buffer);
SCSendOK(pCon);
return 1;
}
}
}
return CountAction(pCon,pSics,pData,argc,argv);
}
/*------------------------------------------------------------------------*/
int MakeMultiCounter(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]){
int i, status;
pCounter pNew = NULL;
char pBueffel[132];
CommandList *pCom;
pICountable pCount;
pMultiCounter self = NULL;
pCounterDriver pDriv = NULL;
/*
need at least two parameters
*/
if(argc < 3){
SCWrite(pCon,"ERROR: insufficient number of arguments to MakeMultiCounter",
eError);
return 0;
}
/*
allocate our data structure
*/
self = malloc(sizeof(MultiCounter));
pDriv = malloc(sizeof(CounterDriver));
if(self == NULL || pDriv == NULL){
SCWrite(pCon,"ERROR: out of memory in MakeMultiCounter",eError);
return 0;
}
memset(self,0,sizeof(MultiCounter));
memset(pDriv,0,sizeof(CounterDriver));
pDriv->pData = self;
pDriv->KillPrivate = KillMultiDriver;
pDriv->iNoOfMonitors = MAXCOUNT;
pNew = CreateCounter(argv[1],pDriv);
if(pNew == NULL){
SCWrite(pCon,"ERROR: out of memory in MakeMultiCounter",eError);
return 0;
}
pDriv->Get = MultiCounterGet;
pDriv->GetError = MultiCounterError;
pDriv->TryAndFixIt = MultiCounterFix;
pDriv->Set = MultiCounterSet;
pDriv->Send
= MultiCounterSend;
/*
assign interface functions
*/
pNew->pCountInt->Halt = MMCCHalt;
pNew->pCountInt->StartCount = MMCCStart;
pNew->pCountInt->CheckCountStatus = MMCCStatus;
pNew->pCountInt->Pause = MMCCPause;
pNew->pCountInt->Continue = MMCCContinue;
pNew->pCountInt->TransferData = MMCCTransfer;
pNew->pCountInt->SetCountParameters = MMCCParameter;
/*
now loop through the remaining arguments, thereby entering them into
the slave list.
*/
for(i = 2; i < argc; i++){
pCom = FindCommand(pSics,argv[i]);
if(!pCom){
sprintf(pBueffel,"ERROR: object %s not found in MakeMultiCounter",
argv[i]);
SCWrite(pCon,pBueffel,eError);
continue;
}
pCount = GetCountableInterface(pCom->pData);
if(!pCount){
sprintf(pBueffel,"ERROR: object %s is NOT countable",
argv[i]);
SCWrite(pCon,pBueffel,eError);
continue;
}
self->slaves[self->nSlaves] = pCount;
self->slaveData[self->nSlaves] = pCom->pData;
self->nSlaves++;
}
/*
now install our action command and we are done
*/
status = AddCommand(pSics,argv[1],MultiCounterAction,DeleteCounter,
pNew);
if(!status){
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[1]);
SCWrite(pCon,pBueffel,eError);
DeleteCounter(pNew);
return 0;
}
return 1;
}

19
multicounter.h Normal file
View File

@ -0,0 +1,19 @@
/**
* The MultiCounter is another counter which coordinates multiple
* counting objects, counters and histogram memories. It also calls a
* script function after TransferData which collects counters and monitors.
* The purpose is to have a flexible counter abstraction for upper level
* code such as maximizers and scan functions. The script can deal with
* counting on monitors or on sums of histogram memories.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, September 2006
*/
#ifndef MULTICOUNTER_H_
#define MULTICOUNTER_H_
#include <sics.h>
int MakeMultiCounter(SConnection *pCon, SicsInterp *pSics,
void *pData, int argc, char *argv[]);
#endif /*MULTICOUNTER_H_*/

View File

@ -315,6 +315,7 @@
char pError[132]; char pError[132];
int i, iToken, iRet; int i, iToken, iRet;
sParser PP; sParser PP;
CommandList *pCom = NULL;
assert(pCon); assert(pCon);
assert(pSics); assert(pSics);
@ -345,9 +346,10 @@
break; break;
case ENDCONFIG: case ENDCONFIG:
/* reconfigure command to final state */ /* reconfigure command to final state */
RemoveCommand(pSics,argv[0]); pCom = FindCommand(pSics,argv[0]);
AddCommand(pSics,argv[0],MultiWrapper,KillMultiMotor, assert(pCom != NULL);
self); pCom->OFunc = MultiWrapper;
pCom->KFunc = KillMultiMotor;
return 1; return 1;
break; break;
case ALIAS: case ALIAS:

View File

@ -424,9 +424,14 @@ CreateSocketAdress(
return 0; return 0;
} }
/*
* Check if the we can write to the socket first....
* Well, this how it should be. However, on linux I observe that
* there is a problem with Java clients not reliably receiving data when
* this is active.
*/
#ifndef CYGNUS #ifndef CYGNUS
/* setup for select first */ tmo.tv_usec = 10;
tmo.tv_usec = 100;
FD_ZERO(&lMask); FD_ZERO(&lMask);
FD_SET(self->sockid,&lMask); FD_SET(self->sockid,&lMask);
if((self->sockid >= FD_SETSIZE) || (self->sockid < 0) ) if((self->sockid >= FD_SETSIZE) || (self->sockid < 0) )
@ -446,6 +451,7 @@ CreateSocketAdress(
return -2; return -2;
} }
#endif #endif
iRet = send(self->sockid,buffer,lLen,0); iRet = send(self->sockid,buffer,lLen,0);
if(iRet != lLen) if(iRet != lLen)
{ {

View File

@ -686,6 +686,9 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */
int iRet, iStatus; int iRet, iStatus;
int iCount; int iCount;
NetItem NItem; NetItem NItem;
int conCount = 0;
char num[50];
IPair *options = NULL;
self = (pNetRead)pData; self = (pNetRead)pData;
assert(self); assert(self);
@ -716,9 +719,13 @@ extern int VerifyChannel(mkChannel *self); /* defined in network.c */
{ {
iCount = NItem.pSock->sockid; iCount = NItem.pSock->sockid;
} }
conCount++;
iRet = LLDnodePtr2Next(self->iList); iRet = LLDnodePtr2Next(self->iList);
} }
snprintf(num,50,"%d", conCount);
IFSetOption(pSICSOptions,"ConnectionCount",num);
/* the select itself */ /* the select itself */
tmo.tv_usec = self->iReadTimeout; tmo.tv_usec = self->iReadTimeout;
iCount++; iCount++;

View File

@ -109,6 +109,8 @@
/* initialise tasker */ /* initialise tasker */
assert(TaskerInit(&self->pTasker)); assert(TaskerInit(&self->pTasker));
pSICSOptions = IFAddOption(pSICSOptions, "ConnectionCount","0");
/* initialise the server from script */ /* initialise the server from script */
if(file == NULL) if(file == NULL)
{ {
@ -397,13 +399,13 @@
*/ */
killTclDrivable(); killTclDrivable();
/* close the List system */
LLDsystemClose();
KillFreeConnections(); KillFreeConnections();
killSICSHipadaba(); killSICSHipadaba();
/* close the List system */
LLDsystemClose();
/* make fortify print his findings */ /* make fortify print his findings */
Fortify_DumpAllMemory(iFortifyScope); Fortify_DumpAllMemory(iFortifyScope);
Fortify_LeaveScope(); Fortify_LeaveScope();

View File

@ -373,6 +373,31 @@ static void putSicsData(SConnection *pCon, SicsInterp *pSics,
} }
} }
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
static void putAttribute(SConnection *pCon, SicsInterp *pSics,
pNXScript self, int argc, char *argv[]){
int status, type = NX_CHAR;
char buffer[256];
if(argc < 5){
SCWrite(pCon,"ERROR: insufficient number of arguments to putAttribute",
eError);
return;
}
status = NXDopenalias(self->fileHandle,self->dictHandle,argv[2]);
if(status != NX_OK){
sprintf(buffer,"ERROR: failed to open alias %s", argv[2]);
SCWrite(pCon,buffer,eError);
return;
}
status = NXputattr(self->fileHandle,argv[3],(void *)argv[4],
strlen(argv[4])+1, type);
if(status != NX_OK){
sprintf(buffer,"ERROR: failed to write attribute %s", argv[3]);
SCWrite(pCon,buffer,eError);
}
}
/*----------------------------------------------------------------------*/
static void updateHMDim(NXScript *self, pHistMem mem){ static void updateHMDim(NXScript *self, pHistMem mem){
int iDim[MAXDIM]; int iDim[MAXDIM];
int i, rank, timeLength, status; int i, rank, timeLength, status;
@ -412,7 +437,7 @@ static void putHistogramMemory(SConnection *pCon, SicsInterp *pSics,
pNXScript self, pNXScript self,
int argc, char *argv[]){ int argc, char *argv[]){
pHistMem mem = NULL; pHistMem mem = NULL;
int status, start, length, i, subset = 0; int status, start, length, i, subset = 0, bank = 0;
HistInt *iData = NULL; HistInt *iData = NULL;
char buffer[256]; char buffer[256];
@ -461,6 +486,19 @@ static void putHistogramMemory(SConnection *pCon, SicsInterp *pSics,
} }
} }
/*
* check for additional bank number
*/
if(argc > 6){
status = Tcl_GetInt(InterpGetTcl(pSics),argv[6],&bank);
if(status != TCL_OK){
sprintf(buffer,"ERROR: failed to convert %s to integer",
argv[6]);
SCWrite(pCon,buffer,eError);
return;
}
}
/* /*
read HM read HM
*/ */
@ -472,7 +510,7 @@ static void putHistogramMemory(SConnection *pCon, SicsInterp *pSics,
return; return;
} }
memset(iData,0,length*sizeof(HistInt)); memset(iData,0,length*sizeof(HistInt));
status = GetHistogramDirect(mem,pCon,0,start,start+length,iData, status = GetHistogramDirect(mem,pCon,bank,start,start+length,iData,
length*sizeof(HistInt)); length*sizeof(HistInt));
}else{ }else{
/* /*
@ -712,7 +750,10 @@ static void putArray(SConnection *pCon, SicsInterp *pSics,
data = (float *)malloc(length*sizeof(float)); data = (float *)malloc(length*sizeof(float));
} }
if(data == NULL){ if(data == NULL){
SCWrite(pCon,"ERROR: out of memory or invalid length",eError); snprintf(buffer,255,
"ERROR: out of memory or invalid length at %s, length = %s",
argv[2],argv[4]);
SCWrite(pCon,buffer,eError);
return; return;
} }
memset(data,0,length*sizeof(float)); memset(data,0,length*sizeof(float));
@ -980,6 +1021,9 @@ static int handlePut(SConnection *pCon, SicsInterp *pSics, pNXScript self,
}else if(strcmp(argv[1],"putsicsdata") == 0){ }else if(strcmp(argv[1],"putsicsdata") == 0){
/*===============*/ /*===============*/
putSicsData(pCon,pSics,self,argc,argv); putSicsData(pCon,pSics,self,argc,argv);
}else if(strcmp(argv[1],"putattribute") == 0){
/*===============*/
putAttribute(pCon,pSics,self,argc,argv);
} else { } else {
SCWrite(pCon,"ERROR: put command not recognised",eError); SCWrite(pCon,"ERROR: put command not recognised",eError);
} }
@ -1032,6 +1076,7 @@ int NXScriptAction(SConnection *pCon, SicsInterp *pSics, void *pData,
pNXScript self = (pNXScript)pData; pNXScript self = (pNXScript)pData;
char *pFile = NULL; char *pFile = NULL;
int status; int status;
char buffer[132];
/* /*
preliminary checks preliminary checks
@ -1095,6 +1140,20 @@ int NXScriptAction(SConnection *pCon, SicsInterp *pSics, void *pData,
return 1; return 1;
} }
if(strcmp(argv[1],"isalias") == 0) {
if(argc < 3) {
SCWrite(pCon,"ERROR: need alias to test",eError);
return 1;
}
if(NXDget(self->dictHandle,argv[2],buffer,131) == NX_OK){
snprintf(buffer,131,"%s = 1", argv[2]);
} else {
snprintf(buffer,131,"%s = 0", argv[2]);
}
SCWrite(pCon,buffer,eValue);
return 1;
}
if(strcmp(argv[1],"makelink") == 0){ if(strcmp(argv[1],"makelink") == 0){
makeLink(pCon,pSics,self,argc,argv); makeLink(pCon,pSics,self,argc,argv);
return 1; return 1;

View File

@ -28,8 +28,9 @@
int iRet; int iRet;
/* Find the motor */ /* Find the motor */
strtolower(pName); strncpy(pBueffel,pName,511);
pMot = FindMotor(pSics,pName); strtolower(pBueffel);
pMot = FindMotor(pSics,pBueffel);
if(!pMot) if(!pMot)
{ {
sprintf(pBueffel,"WARNING: cannot find motor %s",pName); sprintf(pBueffel,"WARNING: cannot find motor %s",pName);
@ -58,8 +59,9 @@
int iRet; int iRet;
/* Find the motor */ /* Find the motor */
strtolower(pName); strncpy(pBueffel,pName,511);
pMot = FindMotor(pSics,pName); strtolower(pBueffel);
pMot = FindMotor(pSics,pBueffel);
if(!pMot) if(!pMot)
{ {
sprintf(pBueffel,"WARNING: cannot find motor %s",pName); sprintf(pBueffel,"WARNING: cannot find motor %s",pName);
@ -95,8 +97,9 @@
char *pText = NULL; char *pText = NULL;
/* find it */ /* find it */
strtolower(pName); strncpy(pBueffel,pName,511);
pVar = FindVariable(pSics,pName); strtolower(pBueffel);
pVar = FindVariable(pSics,pBueffel);
if(!pVar) if(!pVar)
{ {
sprintf(pBueffel,"WARNING: cannot find variable %s",pName); sprintf(pBueffel,"WARNING: cannot find variable %s",pName);

View File

@ -84,7 +84,7 @@
*/ */
if(self->parNode != NULL){ if(self->parNode != NULL){
if(self->parNode->mama == NULL){ if(self->parNode->mama == NULL){
DeleteHipadabaNode(self->parNode); DeleteHipadabaNode(self->parNode,NULL);
} }
} }
free(self); free(self);

13
ofac.c
View File

@ -119,6 +119,9 @@
#include "sicslist.h" #include "sicslist.h"
#include "cone.h" #include "cone.h"
#include "sicshipadaba.h" #include "sicshipadaba.h"
#include "multicounter.h"
#include "sicspoll.h"
#include "statemon.h"
/*----------------------- Server options creation -------------------------*/ /*----------------------- Server options creation -------------------------*/
static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData, static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]) int argc, char *argv[])
@ -214,6 +217,7 @@
AddCommand(pInter,"FileWhere",MacroWhere,WhereKill,NULL); AddCommand(pInter,"FileWhere",MacroWhere,WhereKill,NULL);
*/ */
AddCommand(pInter,"ClientPut",ClientPut,NULL,NULL); AddCommand(pInter,"ClientPut",ClientPut,NULL,NULL);
AddCommand(pInter,"GumPut",GumPut,NULL,NULL);
AddCommand(pInter,"broadcast",Broadcast,NULL,NULL); AddCommand(pInter,"broadcast",Broadcast,NULL,NULL);
AddCommand(pInter,"transact",TransactAction,NULL,NULL); AddCommand(pInter,"transact",TransactAction,NULL,NULL);
AddCommand(pInter,"fulltransact",TransactAction,NULL,NULL); AddCommand(pInter,"fulltransact",TransactAction,NULL,NULL);
@ -274,6 +278,7 @@
AddCommand(pInter,"MakeCounter",MakeCounter,NULL,NULL); AddCommand(pInter,"MakeCounter",MakeCounter,NULL,NULL);
AddCommand(pInter,"MakeO2T",CreateO2T,NULL,NULL); AddCommand(pInter,"MakeO2T",CreateO2T,NULL,NULL);
AddCommand(pInter,"SicsAlias",SicsAlias,NULL,NULL); AddCommand(pInter,"SicsAlias",SicsAlias,NULL,NULL);
AddCommand(pInter,"SicsAlias",DefineAlias,NULL,NULL);
AddCommand(pInter,"DefineAlias",DefineAlias,NULL,NULL); /* M.Z. */ AddCommand(pInter,"DefineAlias",DefineAlias,NULL,NULL); /* M.Z. */
AddCommand(pInter,"MakeHM",MakeHistMemory,NULL,NULL); AddCommand(pInter,"MakeHM",MakeHistMemory,NULL,NULL);
AddCommand(pInter,"VelocitySelector",VelSelFactory,NULL,NULL); AddCommand(pInter,"VelocitySelector",VelSelFactory,NULL,NULL);
@ -328,6 +333,12 @@
InstallSinfox,NULL,NULL); InstallSinfox,NULL,NULL);
AddCommand(pInter,"MakeCone", AddCommand(pInter,"MakeCone",
MakeCone,NULL,NULL); MakeCone,NULL,NULL);
AddCommand(pInter,"MakeMultiCounter",
MakeMultiCounter,NULL,NULL);
AddCommand(pInter,"MakeSicsPoll",
InstallSICSPoll,NULL,NULL);
AddCommand(pInter,"MakeStateMon",
StateMonFactory,NULL,NULL);
/* /*
install site specific commands install site specific commands
@ -396,6 +407,8 @@
RemoveCommand(pSics,"InstallProtocolHandler"); RemoveCommand(pSics,"InstallProtocolHandler");
RemoveCommand(pSics,"InstallSinfox"); RemoveCommand(pSics,"InstallSinfox");
RemoveCommand(pSics,"MakeCone"); RemoveCommand(pSics,"MakeCone");
RemoveCommand(pSics,"MakeMultiCounter");
RemoveCommand(pSics,"MakeStateMon");
/* /*
remove site specific installation commands remove site specific installation commands
*/ */

View File

@ -519,38 +519,13 @@ static int ClimbDrive(SConnection *pCon,char *name, float value)
} }
return 1; return 1;
} }
/*-------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
static int ClimbVariable(pOptimise self, SConnection *pCon, int i) static int findDirection(pOptimise self, pOVarEntry pOvar, SConnection *pCon)
{ {
pOVarEntry pOvar; int status, direction;
void *pData; float varValue;
int status, direction = 1; long oneCount, twoCount;
long oneCount, twoCount, lastCount, currentCount;
float varValue, startValue;
char buffer[256];
int (*CollectFunc)(pScanData self, int iPoint) = NULL;
assert(self);
assert( (i >= 0) && (i < self->iVar));
assert(pCon);
/* get variable data */
DynarGet(self->pVariables,i,&pData);
pOvar = (pOVarEntry)pData;
startValue = pOvar->fCenter;
/*
* prepare scan object
*/
self->pScanner->pCon = pCon;
self->pScanner->pSics = pServ->pSics;
self->pScanner->iNP = 1;
self->pScanner->iMode = self->eCount;
self->pScanner->fPreset = self->fPreset;
/*
* test for upwards direction
*/
varValue = pOvar->fCenter + pOvar->fStep; varValue = pOvar->fCenter + pOvar->fStep;
status = ClimbDrive(pCon,pOvar->pName,varValue); status = ClimbDrive(pCon,pOvar->pName,varValue);
if(!status) if(!status)
@ -584,14 +559,46 @@ static int ClimbDrive(SConnection *pCon,char *name, float value)
if(oneCount > twoCount) if(oneCount > twoCount)
{ {
direction = 1; direction = 1;
lastCount = oneCount;
} }
else else
{ {
direction = -1; direction = -1;
lastCount = twoCount;
} }
return direction;
}
/*-------------------------------------------------------------------------*/
static int ClimbVariable(pOptimise self, SConnection *pCon, int i)
{
pOVarEntry pOvar;
void *pData;
int status, direction = 1;
long oneCount, twoCount, lastCount, currentCount;
float varValue, startValue;
char buffer[256];
int (*CollectFunc)(pScanData self, int iPoint) = NULL;
assert(self);
assert( (i >= 0) && (i < self->iVar));
assert(pCon);
/* get variable data */
DynarGet(self->pVariables,i,&pData);
pOvar = (pOVarEntry)pData;
startValue = pOvar->fCenter;
/*
* prepare scan object
*/
self->pScanner->pCon = pCon;
self->pScanner->pSics = pServ->pSics;
self->pScanner->iNP = 1;
self->pScanner->iMode = self->eCount;
self->pScanner->fPreset = self->fPreset;
direction = findDirection(self,pOvar, pCon);
if(direction < -1){
return direction;
}
/* /*
* drive to the last best position * drive to the last best position
*/ */
@ -601,6 +608,11 @@ static int ClimbDrive(SConnection *pCon,char *name, float value)
{ {
return DRIVEERROR; return DRIVEERROR;
} }
lastCount = ClimbCount(self,pCon);
if(lastCount < 0)
{
return SCANERROR;
}
currentCount = lastCount; currentCount = lastCount;
/* /*

View File

@ -21,6 +21,7 @@
"warning", "warning",
"error", "error",
"hdb", "hdb",
"hdbEvent",
NULL }; NULL };
static int iNoCodes = 11; static int iNoCodes = 13;
#endif #endif

97
polldriv.c Normal file
View File

@ -0,0 +1,97 @@
/**
* This is the sister module to sicspoll which defines the drivers for the
* various modes of polling SICS objects.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, November-December 2006
*/
#include <stdlib.h>
#include <assert.h>
#include <sics.h>
#include <splitter.h>
#include "polldriv.h"
#include "splitter.h"
#include "sicshipadaba.h"
/*================ actual driver implementation =========================*/
static int timeDue(struct __POLLDRIV *self, time_t now, SConnection *pCon){
if(now > self->nextPoll){
return 1;
} else {
return 0;
}
}
/*------------------ HDB Driver -----------------------------------------*/
static int pollHdb(struct __POLLDRIV *self, SConnection *pCon){
hdbValue old, newVal;
pHdb node = NULL;
memset(&old,0,sizeof(hdbValue));
memset(&newVal,0,sizeof(hdbValue));
node = (pHdb)self->objPointer;
assert(node != NULL);
old = node->value;
self->nextPoll = time(NULL) + self->pollIntervall;
if(GetHipadabaPar(node, &newVal, pCon) == 1){
if(!compareHdbValue(old,newVal)){
UpdateHipadabaPar(node,newVal,pCon);
}
return 1;
} else {
return 0;
}
}
/*-----------------------------------------------------------------------*/
static pPollDriv makeHdbDriver(SConnection *pCon, char *objectIdentifier,
int argc, char *argv[]){
pHdb root = NULL, node = NULL;
pPollDriv pNew = NULL;
root = GetHipadabaRoot();
assert(root != NULL);
node = GetHipadabaNode(root,objectIdentifier);
if(node == NULL){
SCWrite(pCon,"ERROR: object to poll not found",eError);
return 0;
}
pNew = malloc(sizeof(PollDriv));
if(pNew == NULL){
return NULL;
}
memset(pNew,0,sizeof(PollDriv));
pNew->objectIdentifier = strdup(objectIdentifier);
pNew->objPointer = node;
pNew->isDue = timeDue;
pNew->poll = pollHdb;
if(argc > 0){
pNew->pollIntervall = atoi(argv[0]);
} else {
pNew->pollIntervall = 10;
}
return pNew;
}
/*================ external interface ====================================*/
pPollDriv makePollDriver(SConnection *pCon, char *driver,
char *objectIdentifier, int argc, char *argv[]){
strtolower(driver);
if(strcmp(driver,"hdb") == 0) {
return makeHdbDriver(pCon,objectIdentifier, argc, argv);
} else {
SCWrite(pCon,"ERROR: polling driver type unknown",eError);
return NULL;
}
}
/*------------------------------------------------------------------------*/
void deletePollDriv(pPollDriv self){
if(self->objectIdentifier != NULL){
free(self->objectIdentifier);
}
free(self);
}

42
polldriv.h Normal file
View File

@ -0,0 +1,42 @@
/**
* This is the sister module to sicspoll which defines the drivers for the
* various modes of polling SICS objects.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, November-December 2006
*/
#ifndef POLLDRIV_H_
#define POLLDRIV_H_
#include <time.h>
#include <sics.h>
/*==================== a data structure ===================================*/
typedef struct __POLLDRIV{
char *objectIdentifier; /* the object identifier */
void *objPointer; /* a pointer to the object */
time_t nextPoll; /* next polling time */
int pollIntervall; /* poll intervall */
int (*isDue)(struct __POLLDRIV *self, time_t now, SConnection *pCon);
/* function called to determine if this object must be polled */
int (*poll)(struct __POLLDRIV *self, SConnection *pCon);
/* the actual polling function */
}PollDriv, *pPollDriv;
/*==================== the interface =====================================*/
/*
* make a poll driver
* @param pCon A connection to report errors too
* @param driver the driver type to generate
* @param objectIdentifier An identifer for the object to poll
* @param argc number of additional parameter
* @param *argv[] Additional parameters.
* @return NULL on failure or a PollDriv strucure else.
*/
pPollDriv makePollDriver(SConnection *pCon, char *driver,
char *objectIdentifier, int argc, char *argv[]);
/**
* free all memory associated with this poll driver
* @param self The structure to delete
*/
void deletePollDriv(pPollDriv self);
#endif /*POLLDRIV_H_*/

88
polldriv.tc Normal file
View File

@ -0,0 +1,88 @@
/**
* This is the sister module to sicspoll which defines the drivers for the
* various modes of polling SICS objects.
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, November-December 2006
*/
<%! source sicstemplates.tcl %>
<% stdIncludes %>
#include "polldriv.h"
#include "splitter.h"
#include "sicshipadaba.h"
/*================ actual driver implementation =========================*/
static int timeDue(struct __POLLDRIV *self, time_t now, SConnection *pCon){
if(now > self->nextPoll){
return 1;
} else {
return 0;
}
}
/*------------------ HDB Driver -----------------------------------------*/
static int pollHdb(struct __POLLDRIV *self, SConnection *pCon){
hdbValue old, newVal;
pHdb node = NULL;
memset(&old,0,sizeof(hdbValue));
memset(&newVal,0,sizeof(hdbValue));
node = (pHdb)self->objPointer;
assert(node != NULL);
old = node->value;
self->nextPoll = time(NULL) + self->pollIntervall;
if(GetHipadabaPar(node, &newVal, pCon) == 1){
if(!compareHdbValue(old,newVal)){
UpdateHipadabaPar(node,newVal,pCon);
}
return 1;
} else {
return 0;
}
}
/*-----------------------------------------------------------------------*/
static pPollDriv makeHdbDriver(SConnection *pCon, char *objectIdentifier,
int argc, char *argv[]){
pHdb root = NULL, node = NULL;
pPollDriv pNew = NULL;
root = GetHipadabaRoot();
assert(root != NULL);
node = GetHipadabaNode(root,objectIdentifier);
if(node == NULL){
SCWrite(pCon,"ERROR: object to poll not found",eError);
return 0;
}
<%newStruc PollDriv 5 %>
pNew->objectIdentifier = strdup(objectIdentifier);
pNew->objPointer = node;
pNew->isDue = timeDue;
pNew->poll = pollHdb;
if(argc > 0){
pNew->pollIntervall = atoi(argv[0]);
} else {
pNew->pollIntervall = 10;
}
return pNew;
}
/*================ external interface ====================================*/
pPollDriv makePollDriver(SConnection *pCon, char *driver,
char *objectIdentifier, int argc, char *argv[]){
strtolower(driver);
if(strcmp(driver,"hdb") == 0) {
return makeHdbDriver(pCon,objectIdentifier, argc, argv);
} else {
SCWrite(pCon,"ERROR: polling driver type unknown",eError);
return NULL;
}
}
/*------------------------------------------------------------------------*/
void deletePollDriv(pPollDriv self){
if(self->objectIdentifier != NULL){
free(self->objectIdentifier);
}
free(self);
}

View File

@ -16,7 +16,7 @@
#include <dynstring.h> #include <dynstring.h>
#include "commandlog.h" #include "commandlog.h"
#include "protocol.h" #include "protocol.h"
#include "json.h" #include <json/json.h>
#define MAXMSG 1024 #define MAXMSG 1024
#define INIT_STR_SIZE 256 #define INIT_STR_SIZE 256
@ -87,8 +87,6 @@ pProtocol CreateProtocol(void);
static int ProtocolOptions(SConnection* pCon, pProtocol pPro); static int ProtocolOptions(SConnection* pCon, pProtocol pPro);
static int ProtocolHelp(SConnection* pCon, Protocol* pPro); static int ProtocolHelp(SConnection* pCon, Protocol* pPro);
static int ProtocolSet(SConnection* pCon, Protocol* pPro, char *pProName); static int ProtocolSet(SConnection* pCon, Protocol* pPro, char *pProName);
static int ProtocolGet(SConnection* pCon, Protocol* pPro, char *pProName,
int *pIndex);
static int ProtocolList(SConnection* pCon, Protocol* pPro); static int ProtocolList(SConnection* pCon, Protocol* pPro);
int ProtocolAction(SConnection *pCon, SicsInterp *pSics, void *pData, int ProtocolAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
@ -294,9 +292,10 @@ static int ProtocolSet(SConnection* pCon, Protocol* pPro, char *pProName)
} }
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
static int ProtocolGet(SConnection* pCon, Protocol* pPro, char *pProName, int ProtocolGet(SConnection* pCon, void* pData, char *pProName, int len)
int *pIndex)
{ {
int Index;
Protocol *pPro = (Protocol *)pData;
if(!SCVerifyConnection(pCon)) if(!SCVerifyConnection(pCon))
{ {
return 0; return 0;
@ -309,24 +308,27 @@ static int ProtocolGet(SConnection* pCon, Protocol* pPro, char *pProName,
pPro->isDefaultSet = 1; pPro->isDefaultSet = 1;
pCon->iProtocolID = 0; pCon->iProtocolID = 0;
} }
strncpy(pProName, pPro->pProList[pCon->iProtocolID], len);
*pIndex = (int)malloc(sizeof(int)); return 1;
*pIndex = pCon->iProtocolID; #if 0
Index = pCon->iProtocolID;
/* check list of protocols for valid name */ /* check list of protocols for valid name */
switch(*pIndex) switch(Index)
{ {
case 0: /* default = psi_sics */ case 0: /* default = psi_sics */
case 1: /* normal (connection start default) */ case 1: /* normal (connection start default) */
case 2: /* outcodes */ case 2: /* outcodes */
case 3: /* sycamore */ case 3: /* sycamore */
pProName = strdup(pPro->pProList[*pIndex]); case 4: /* json */
pProName = pPro->pProList[Index];
return 1; return 1;
break; break;
default: default:
return 0; return 0;
break; break;
} }
#endif
} }
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
@ -632,42 +634,43 @@ struct json_object *mkJSON_Object(SConnection *pCon, char *pBuffer, int iOut)
json_object_object_add(msg_json, "flag", json_object_new_string(pCode[iOut])); json_object_object_add(msg_json, "flag", json_object_new_string(pCode[iOut]));
break; break;
} }
if (iOut == eHdb) { if (iOut == eHdbValue || iOut == eHdbEvent) {
tmp_json = json_tokener_parse(pBuffer); tmp_json = json_tokener_parse(pBuffer);
if (is_error(msg_json)) { linenum = __LINE__; goto reporterr; } if (is_error(tmp_json)) { linenum = __LINE__; goto reporterr; }
} else { } else {
/* Strip \r and \n */ /* Strip \r and \n */
for (pBufferFrom=pBufferTo=pBuffer; ; pBufferFrom++) { for (pBufferFrom=pBufferTo=pBuffer; ; pBufferFrom++) {
if (*pBufferFrom == '\r' || *pBufferFrom == '\n') if (*pBufferFrom == '\r' || *pBufferFrom == '\n')
continue; continue;
*pBufferTo = *pBufferFrom; pBufferTo = pBufferFrom;
if (*pBufferTo == '\0') if (*pBufferTo == '\0')
break; break;
pBufferTo++; pBufferTo++;
} }
tmp_json = json_object_new_string(pBuffer); tmp_json = json_object_new_string(pBuffer);
if (is_error(msg_json)) { linenum = __LINE__; goto reporterr; } if (is_error(tmp_json)) { linenum = __LINE__; goto reporterr; }
} }
json_object_object_add(msg_json, "data", tmp_json); json_object_object_add(msg_json, "data", tmp_json);
return msg_json; return msg_json;
reporterr: reporterr:
SCSetWriteFunc(pCon,SCNormalWrite); SCSetWriteFunc(pCon,SCNormalWrite);
snprintf(pError, 256,"%s:%d Error making json object", __FILE__, linenum); snprintf(pError, 256,"{\"ERROR\": \"%s:%d Error making json object\"}", __FILE__, linenum);
SCWrite(pCon,pError,eError); SCWrite(pCon,pError,eError);
SCSetWriteFunc(pCon,SCWriteJSON_String);
cleanup: cleanup:
if (tmp_json != NULL) if (tmp_json != NULL && !is_error(tmp_json))
json_object_put(tmp_json); json_object_put(tmp_json);
if (msg_json != NULL) if (msg_json != NULL && !is_error(msg_json))
json_object_put(msg_json); json_object_put(msg_json);
return NULL; return NULL;
} }
int SCWriteJSON_String(SConnection *pCon, char *pBuffer, int iOut) int SCWriteJSON_String(SConnection *pCon, char *pBuffer, int iOut)
{ {
struct json_object *my_object=NULL; struct json_object *my_object=NULL, *tmp_json=NULL;
char pBueffel[MAXMSG]; char pBueffel[MAXMSG], errBuff[MAXMSG];
int iRet; int iRet, errLen = MAXMSG;
if (strlen(pBuffer) == 0) if (strlen(pBuffer) == 0)
return 1; return 1;
@ -687,22 +690,49 @@ int SCWriteJSON_String(SConnection *pCon, char *pBuffer, int iOut)
/* write to commandlog if user or manager privilege */ /* write to commandlog if user or manager privilege */
if(SCGetRights(pCon) <= usUser) if(SCGetRights(pCon) <= usUser)
{
if(pCon->iMacro != 1)
{ {
sprintf(pBueffel,"To sock %d :",iRet); sprintf(pBueffel,"To sock %d :",iRet);
WriteToCommandLog(pBueffel,pBuffer); WriteToCommandLog(pBueffel,pBuffer);
} }
else
{
if(iOut == eError || iOut == eWarning)
{
sprintf(pBueffel,"To sock %d :",iRet);
WriteToCommandLog(pBueffel,pBuffer);
}
}
}
if(SCinMacro(pCon)) if(SCinMacro(pCon))
{ {
InterpWrite(pServ->pSics,pBuffer); InterpWrite(pServ->pSics,pBuffer);
/* print it to client if error message */
if((iOut== eError) || (iOut == eWarning) )
{
tmp_json = json_object_new_string(pBuffer);
iRet = SCDoSockWrite(pCon,json_object_to_json_string(tmp_json));
}
} else {
if ((my_object = mkJSON_Object(pCon, pBuffer, iOut)) == NULL) {
snprintf(errBuff, errLen, "failed to make JSON object from, %s", pBuffer);
tmp_json = json_object_new_string(errBuff);
my_object = json_object_new_object();
json_object_object_add(my_object, "ERROR", tmp_json);
SCDoSockWrite(pCon,json_object_to_json_string(my_object));
iRet = 0;
} else { } else {
my_object = mkJSON_Object(pCon, pBuffer, iOut);
iRet = SCDoSockWrite(pCon,json_object_to_json_string(my_object)); iRet = SCDoSockWrite(pCon,json_object_to_json_string(my_object));
SCWriteToLogFiles(pCon,pBuffer); SCWriteToLogFiles(pCon,pBuffer);
} }
if (my_object != NULL) }
if (tmp_json != NULL && !is_error(tmp_json))
json_object_put(tmp_json);
if (my_object != NULL && !is_error(my_object))
json_object_put(my_object); json_object_put(my_object);
return 1; return iRet;
} }
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Protocol API */ /* Protocol API */
@ -731,6 +761,7 @@ char * GetProtocolName(SConnection* pCon)
case 1: /* normal (connection start default) */ case 1: /* normal (connection start default) */
case 2: /* outcodes */ case 2: /* outcodes */
case 3: /* sycamore */ case 3: /* sycamore */
case 4: /* json */
return strdup(pPro->pProList[pCon->iProtocolID]); return strdup(pPro->pProList[pCon->iProtocolID]);
break; break;
default: default:

View File

@ -30,5 +30,6 @@ int SCWriteSycamore(SConnection *pCon, char *pBuffer, int iOut);
/*--------------------- implement protocol API -----------------------*/ /*--------------------- implement protocol API -----------------------*/
char * GetProtocolName(SConnection *pCon); char * GetProtocolName(SConnection *pCon);
int GetProtocolID(SConnection *pCon); int GetProtocolID(SConnection *pCon);
int ProtocolGet(SConnection* pCon, void* pData, char *pProName, int len);
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#endif #endif

262
regresscter.c Normal file
View File

@ -0,0 +1,262 @@
/*--------------------------------------------------------------------------
This is a counter for use in automated regression tests.
copyright: see file COPYRIGHT
Mark Koennecke, September 2006
----------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <time.h>
#include "fortify.h"
#include <string.h>
#include "sics.h"
#include "countdriv.h"
/*---------------------------------- possible error types ------------------*/
#define NONE 0
#define STARTFAIL 1
#define STATUSFAIL 2
#define PAUSEFAIL 3
#define CONTFAIL 4
#define READFAIL 5
#define STATEIDLE 0
#define STATERUN 1
#define STATEPAU 2
/*--------------------------------------------------------------------------*/
typedef struct {
int errType;
int recover;
int state;
time_t endTime;
} RegressSt;
/*---------------------------------------------------------------------------*/
static int RegressGetStatus(struct __COUNTER *self, float *fControl){
RegressSt *pSim = NULL;
time_t tD, tDe;
int iRun;
assert(self);
pSim = (RegressSt *) self->pData;
assert(pSim);
if(pSim->errType == STATUSFAIL){
return HWFault;
}
if(time(NULL) > pSim->endTime){
pSim->state = STATEIDLE;
}
switch(pSim->state){
case STATEIDLE:
return HWIdle;
break;
case STATERUN:
return HWBusy;
break;
case STATEPAU:
return HWPause;
break;
}
assert(0);
return HWFault;
}
/*---------------------------------------------------------------------------*/
static int RegressStart(struct __COUNTER *self){
RegressSt *pSim = NULL;
time_t tD;
int iRun;
assert(self);
pSim = (RegressSt *) self->pData;
assert(pSim);
if(pSim->errType == STARTFAIL){
return HWFault;
}
pSim->state = STATERUN;
if(self->eMode == eTimer){
pSim->endTime = time(NULL) + (int)self->fPreset;
} else {
pSim->endTime = time(NULL) + 7;
}
return OKOK;
}
/*---------------------------------------------------------------------------*/
static int RegressPause(struct __COUNTER *self){
RegressSt *pSim = NULL;
time_t tD;
int iRun;
assert(self);
pSim = (RegressSt *) self->pData;
assert(pSim);
if(pSim->errType == PAUSEFAIL){
return HWFault;
}
pSim->state = STATEPAU;
return OKOK;
}
/*---------------------------------------------------------------------------*/
static int RegressContinue(struct __COUNTER *self){
RegressSt *pSim = NULL;
assert(self);
pSim = (RegressSt *) self->pData;
assert(pSim);
if(pSim->errType == CONTFAIL){
return HWFault;
}
pSim->state = STATERUN;
return OKOK;
}
/*--------------------------------------------------------------------------*/
static int RegressHalt(struct __COUNTER *self){
RegressSt *pSim = NULL;
assert(self);
pSim = (RegressSt *) self->pData;
assert(pSim);
pSim->state = STATEIDLE;
return OKOK;
}
/*-------------------------------------------------------------------------*/
static int RegressReadValues(struct __COUNTER *self){
RegressSt *pSim = NULL;
int i;
assert(self);
pSim = (RegressSt *) self->pData;
assert(pSim);
if(pSim->errType == READFAIL){
return HWFault;
}
for (i = 0; i < MAXCOUNT; i++) {
self->lCounts[i] = i*10+5;
}
self->lCounts[1] = self->fPreset;
self->fTime = self->fPreset;
return OKOK;
}
/*-------------------------------------------------------------------------*/
static int RegressGetError(struct __COUNTER *self, int *iCode, char *error,
int iErrLen){
strncpy(error, "Regression counter error", iErrLen);
*iCode = 1;
return 1;
}
/*--------------------------------------------------------------------------*/
static int RegressTryAndFixIt(struct __COUNTER *self, int iCode){
RegressSt *pSim = NULL;
assert(self);
pSim = (RegressSt *) self->pData;
assert(pSim);
if(pSim->recover == 1){
pSim->errType = NONE;
return COREDO;
} else {
return COTERM;
}
}
/*--------------------------------------------------------------------------*/
static int RegressSet(struct __COUNTER *self, char *name, int iCter, float FVal){
RegressSt *pSim = NULL;
assert(self);
pSim = (RegressSt *) self->pData;
assert(pSim);
if(strcmp(name,"errortype") == 0){
pSim->errType = (int)FVal;
return 1;
}
if(strcmp(name,"recover") == 0){
pSim->recover = (int)FVal;
return 1;
}
if(strcmp(name,"finish") == 0){
pSim->state = STATEIDLE;
return 1;
}
return 0;
}
/*--------------------------------------------------------------------------*/
static int RegressGet(struct __COUNTER *self, char *name,
int iCter, float *fVal){
RegressSt *pSim = NULL;
assert(self);
pSim = (RegressSt *) self->pData;
assert(pSim);
if(strcmp(name,"errortype") == 0){
*fVal = pSim->errType;
return 1;
}
if(strcmp(name,"recover") == 0){
*fVal = pSim->recover;
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
static int RegressSend(struct __COUNTER *self, char *pText,
char *pReply, int iReplyLen){
strncpy(pReply, "Simulated response", iReplyLen);
return 1;
}
/*---------------------------------------------------------------------------*/
pCounterDriver NewRegressCounter(char *name){
pCounterDriver pRes = NULL;
RegressSt *pData = NULL;
int iRet;
int iC1, iC2, iC3;
char *pErr;
char pBueffel[132];
pRes = CreateCounterDriver(name, "Regress");
if (!pRes) {
return NULL;
}
pData = (RegressSt *) malloc(sizeof(RegressSt));
if (!pData) {
DeleteCounterDriver(pRes);
return NULL;
}
memset(pData,0,sizeof(RegressSt));
pRes->pData = pData;
/*
* assign functions
*/
pRes->GetStatus = RegressGetStatus;
pRes->Start = RegressStart;
pRes->Halt = RegressHalt;
pRes->ReadValues = RegressReadValues;
pRes->GetError = RegressGetError;
pRes->TryAndFixIt = RegressTryAndFixIt;
pRes->Pause = RegressPause;
pRes->Continue = RegressContinue;
pRes->Set = RegressSet;
pRes->Get = RegressGet;
pRes->Send = RegressSend;
pRes->KillPrivate = NULL;
pRes->iNoOfMonitors = 8;
return pRes;
}

View File

@ -19,6 +19,7 @@ M. Zolliker July 04
#include "status.h" #include "status.h"
#include "servlog.h" #include "servlog.h"
#include "site.h" #include "site.h"
#include "commandlog.h"
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#define INTERRUPTMODE 0 #define INTERRUPTMODE 0
#define ACCESSCODE 1 #define ACCESSCODE 1
@ -242,8 +243,10 @@ static int RemServerTask(void *data) {
rc = &remserver->rc[isUser]; rc = &remserver->rc[isUser];
if (RemRead(rc, 0) <= 0) continue; if (RemRead(rc, 0) <= 0) continue;
/* printf("< %s\n", buf); */ if (strstr(rc->line, " ") == rc->line) {
WriteToCommandLog("REMOB>", "infinite echo loop detected");
continue;
}
if (isUser == 0) { if (isUser == 0) {
if (RemHandle(remserver)) { /* handle drivstat messages */ if (RemHandle(remserver)) { /* handle drivstat messages */
continue; continue;

View File

@ -434,6 +434,42 @@ void getRS232Error(int iCode, char *errorBuffer,
} }
} }
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
int fixRS232Error(prs232 self, int iCode){
int i, status, read;
char buffer[8192];
switch(iCode){
case BADMEMORY:
case FAILEDCONNECT:
return 0;
break;
case INCOMPLETE:
case TIMEOUT:
/*
* try to clear possibly pending stuff
*/
for(i = 0; i < 3; i++){
if(availableRS232(self)){
read = 8192;
readRS232(self,buffer,&read);
}
}
return 1;
break;
case NOTCONNECTED:
case BADSEND:
closeRS232(self);
status = initRS232(self);
if(status){
return 1;
} else {
return 0;
}
break;
}
return 0;
}
/*--------------------------------------------------------------------*/
int getRS232Timeout(prs232 self){ int getRS232Timeout(prs232 self){
return self->timeout; return self->timeout;
} }

View File

@ -65,6 +65,7 @@
void getRS232Error(int iCode, char *errorBuffer, void getRS232Error(int iCode, char *errorBuffer,
int errorBufferLen); int errorBufferLen);
int fixRS232Error(prs232 self, int iCode);
int getRS232Timeout(prs232 self); int getRS232Timeout(prs232 self);
int initRS232(prs232 self); int initRS232(prs232 self);
int initRS232WithFlags(prs232 self, int flags); int initRS232WithFlags(prs232 self, int flags);

19
scan.c
View File

@ -385,6 +385,7 @@ int AppendScanLine(pScanData self, char *line)
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
extern char *stptok(const char *s, char *t, int len, char *brk); extern char *stptok(const char *s, char *t, int len, char *brk);
extern char *trim(char *txt);
int StoreScanCounts(pScanData self, char *data) int StoreScanCounts(pScanData self, char *data)
{ {
@ -402,7 +403,7 @@ int StoreScanCounts(pScanData self, char *data)
InitCountEntry(&sCount); InitCountEntry(&sCount);
/* parse the data */ /* parse the data */
pPtr = data; pPtr = trim(data);
pPtr = stptok(pPtr,pNumber,29," \t"); pPtr = stptok(pPtr,pNumber,29," \t");
if(pPtr != NULL) if(pPtr != NULL)
{ {
@ -1584,7 +1585,7 @@ static int PrintTimes(pScanData self, SConnection *pCon,
snprintf(pBueffel,59,"%s.scantimes = { ",name); snprintf(pBueffel,59,"%s.scantimes = { ",name);
DynStringCopy(data,pBueffel); DynStringCopy(data,pBueffel);
for(i = 0; i < self->iNP; i++) for(i = 0; i < self->iCounts; i++)
{ {
DynarGet(self->pCounts,i,&pPtr); DynarGet(self->pCounts,i,&pPtr);
pData = (pCountEntry)pPtr; pData = (pCountEntry)pPtr;
@ -2414,6 +2415,20 @@ static int DumpScan(pScanData self, SConnection *pCon)
} }
return AppendVarPos(pCon,self,i,(float)fStep); return AppendVarPos(pCon,self,i,(float)fStep);
} }
else if(strcmp(argv[1],"softpos") == 0){
if(argc > 2) {
if(!SCMatchRights(pCon,usMugger)){
return 0;
}
self->posSoft = atoi(argv[2]);
SCSendOK(pCon);
return 1;
} else {
sprintf(pBueffel,"%s.softpos = %d", argv[0],self->posSoft);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
}
/*------- savecounter */ /*------- savecounter */
else if(strcmp(argv[1],"savecounter") == 0) else if(strcmp(argv[1],"savecounter") == 0)
{ {

2
sics.h
View File

@ -17,7 +17,7 @@
/* the following line suppresses const declarations in tcl.h. /* the following line suppresses const declarations in tcl.h.
-> makes the compiler happy M.Z. */ -> makes the compiler happy M.Z. */
#define NO_CONST /* #define NO_CONST */
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>

View File

@ -11,7 +11,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <time.h> #include <time.h>
#include <tcl.h> #include "macro.h"
#include "fortify.h" #include "fortify.h"
#include "sics.h" #include "sics.h"
#include "splitter.h" #include "splitter.h"
@ -24,6 +24,7 @@
char *pCommand; char *pCommand;
SConnection *pCon; SConnection *pCon;
int iEnd; int iEnd;
Statistics *stat;
} Cron, *pCron; } Cron, *pCron;
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
@ -43,12 +44,19 @@
{ {
SCDeleteConnection(self->pCon); SCDeleteConnection(self->pCon);
} }
if (self->stat) {
StatisticsKill(self->stat);
}
free(self); free(self);
} }
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static int CronTask(void *pData) static int CronTask(void *pData)
{ {
Statistics *old;
pCron self = (pCron)pData; pCron self = (pCron)pData;
int iRet;
Tcl_Interp *pTcl = pServ->pSics->pTcl;
if(!self) if(!self)
{ {
@ -57,7 +65,17 @@
if(time(NULL) > self->tNext) if(time(NULL) > self->tNext)
{ {
SCInvoke(self->pCon,pServ->pSics,self->pCommand); MacroPush(self->pCon);
old=StatisticsBegin(self->stat);
iRet = Tcl_Eval(pTcl,self->pCommand);
StatisticsEnd(old);
MacroPop();
if (iRet != TCL_OK) {
SCPrintf(self->pCon, eStatus,
"ERROR in sicscron script: %s", pTcl->result);
self->iEnd = 0;
return 0;
}
self->tNext = time(NULL) + self->iIntervall; self->tNext = time(NULL) + self->iIntervall;
} }
return self->iEnd; return self->iEnd;
@ -82,11 +100,11 @@
int argc, char *argv[]) int argc, char *argv[])
{ {
pCron pNew = NULL; pCron pNew = NULL;
int iVal, iRet; int iVal, iRet, rights;
char *cmd; char *cmd;
/* only managers may do this */ /* need user priv. */
if(!SCMatchRights(pCon,usMugger)) if(!SCMatchRights(pCon,usUser))
{ {
return 0; return 0;
} }
@ -123,10 +141,16 @@
SCWrite(pCon,"ERROR: out of memory in sicscron",eError); SCWrite(pCon,"ERROR: out of memory in sicscron",eError);
return 0; return 0;
} }
rights = SCGetRights(pCon);
if (rights > usMugger) {
/* transfer the rights to the dummy connection */
SCSetRights(pNew->pCon, rights);
}
pNew->iIntervall = iVal; pNew->iIntervall = iVal;
pNew->pCommand = cmd; pNew->pCommand = cmd;
pNew->tNext = 0; pNew->tNext = 0;
pNew->iEnd = 1; pNew->iEnd = 1;
pNew->stat = StatisticsNew(cmd);
TaskRegister(pServ->pTasker, TaskRegister(pServ->pTasker,
CronTask, CronTask,

View File

@ -4,6 +4,8 @@
An attempt to a generic interface to SICS data for all sorts of SICS An attempt to a generic interface to SICS data for all sorts of SICS
clients. clients.
WARNING: this code only works when ints and floats are of the same size!
copyright: see file COPYRIGHT copyright: see file COPYRIGHT
Mark Koennecke, June 2003 Mark Koennecke, June 2003
@ -17,7 +19,7 @@
#include "scan.h" #include "scan.h"
#include "HistMem.h" #include "HistMem.h"
#include "sicsdata.h" #include "sicsdata.h"
#define ABS(x) (x < 0 ? -(x) : (x))
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
static void KillSICSData(void *pData){ static void KillSICSData(void *pData){
pSICSData self = NULL; pSICSData self = NULL;
@ -60,6 +62,47 @@ pSICSData createSICSData(void){
pNew->dataUsed = 0; pNew->dataUsed = 0;
return pNew; return pNew;
} }
/*---------------------------------------------------------------------------*/
int getSICSDataInt(pSICSData self, int pos, int *value){
if(pos >= self->dataUsed || self->dataType[pos] != INTTYPE){
return 0;
}
*value = self->data[pos];
return 1;
}
/*---------------------------------------------------------------------------*/
int getSICSDataFloat(pSICSData self, int pos, float *value){
if(pos >= self->dataUsed || self->dataType[pos] != FLOATTYPE){
return 0;
}
memcpy(value,&self->data[pos],sizeof(float));
return 1;
}
/*---------------------------------------------------------------------------*/
int setSICSDataInt(pSICSData self, int pos, int value){
int *idata = NULL;
idata = getSICSDataPointer(self,0,pos+1);
if(idata == NULL){
return 0;
}
idata[pos] = value;
self->dataType[pos] = INTTYPE;
return 1;
}
/*----------------------------------------------------------------------------*/
int setSICSDataFloat(pSICSData self, int pos, float value){
int *idata = NULL;
idata = getSICSDataPointer(self,0,pos+1);
if(idata == NULL){
return 0;
}
memcpy(&idata[pos],&value,sizeof(float));
self->dataType[pos] = FLOATTYPE;
return 1;
}
/*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/
int *getSICSDataPointer(pSICSData self, int start, int end){ int *getSICSDataPointer(pSICSData self, int start, int end){
int newSize; int newSize;
@ -134,7 +177,7 @@ static void netEncode(pSICSData self){
} }
} }
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
static void clearSICSData(pSICSData self){ void clearSICSData(pSICSData self){
assert(self); assert(self);
self->dataUsed = 0; self->dataUsed = 0;
@ -236,6 +279,74 @@ static int putFloat(pSICSData self, int argc, char *argv[],
SCSendOK(pCon); SCSendOK(pCon);
return 1; return 1;
} }
/*------------------------------------------------------------------*/
static int getPos(pSICSData self, char *name,
SConnection *pCon, int pos){
char pBueffel[512];
float value;
if(pos >= self->dataUsed){
SCWrite(pCon,"ERROR: requested position out of range",eError);
return 0;
}
if(self->dataType[pos] == FLOATTYPE){
memcpy(&value,&self->data[pos],sizeof(float));
snprintf(pBueffel,511,"%s = %f", name, value);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
if(self->dataType[pos] == INTTYPE){
snprintf(pBueffel,511,"%s = %d", name, self->data[pos]);
SCWrite(pCon,pBueffel,eValue);
return 1;
}
return 0;
}
/*------------------------------------------------------------------*/
static float getDataPos(pSICSData self, int pos){
float value;
assert(pos < self->dataUsed);
if(self->dataType[pos] == FLOATTYPE){
memcpy(&value,&self->data[pos],sizeof(float));
} else {
value = (float)self->data[pos];
}
return value;
}
/*------------------------------------------------------------------*/
static int divideSicsData(pSICSData self, SicsInterp *pSics,
SConnection *pCon, char *name){
int i;
pSICSData other = NULL;
float val, div;
other = (pSICSData)FindCommandData(pSics,name,"SICSData");
if(other == NULL){
SCWrite(pCon,"ERROR: requested SICSData object to divide not found",
eError);
return 0;
}
if(other->dataUsed < self->dataUsed){
SCWrite(pCon,"ERROR: not enough data in SICSData for division",
eError);
return 0;
}
for(i = 0; i < self->dataUsed; i++){
div = getDataPos(other,i);
if(ABS(div) > .00001){
val = getDataPos(self,i)/div;
} else {
val = .0;
}
if(self->dataType[i] == INTTYPE){
self->data[i] = (int)val;
} else {
memcpy(&self->data[i],&val,sizeof(float));
}
}
return 1;
}
/*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/
static int copyScanCounts(pSICSData self, int argc, char *argv[], static int copyScanCounts(pSICSData self, int argc, char *argv[],
SConnection *pCon, SicsInterp *pSics){ SConnection *pCon, SicsInterp *pSics){
@ -475,6 +586,35 @@ static int copyHM(pSICSData self, int argc, char *argv[],
SCSendOK(pCon); SCSendOK(pCon);
return 1; return 1;
} }
/*----------------------------------------------------------------------*/
static int copyData(pSICSData self,SicsInterp *pSics,
SConnection *pCon,int argc, char *argv[]){
pSICSData other = NULL;
int pos, start, end, i;
if(argc < 6){
SCWrite(pCon,"ERROR: Insufficient number of arguments to copydata",
eError);
return 0;
}
pos = atoi(argv[2]);
start = atoi(argv[4]);
end = atoi(argv[5]);
if((other = FindCommandData(pSics,argv[3],"SICSData")) == NULL){
SCWrite(pCon,"ERROR: invalid SICSData requested",eError);
return 0;
}
if(start > end || end > other->dataUsed){
SCWrite(pCon,"ERROR: invalid copy range specified",eError);
return 0;
}
getSICSDataPointer(self,pos, pos + (end -start));
memcpy(&self->data[pos],&other->data[start],(end-start)*sizeof(int));
memcpy(&self->dataType[pos],&other->dataType[start],
(end-start)*sizeof(char));
return 1;
}
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
Look here in order to find out about commands understood Look here in order to find out about commands understood
----------------------------------------------------------------------*/ ----------------------------------------------------------------------*/
@ -482,6 +622,7 @@ int SICSDataAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){ int argc, char *argv[]){
pSICSData self = NULL; pSICSData self = NULL;
char pBueffel[132]; char pBueffel[132];
int pos;
self = (pSICSData)pData; self = (pSICSData)pData;
assert(self); assert(self);
@ -509,6 +650,21 @@ int SICSDataAction(SConnection *pCon, SicsInterp *pSics, void *pData,
return 0; return 0;
} }
return dumpSICSData(self,argv[2],pCon); return dumpSICSData(self,argv[2],pCon);
} else if(strcmp(argv[1],"get") == 0){
if(argc < 3){
SCWrite(pCon,"ERROR: need a position to read",eError);
return 0;
}
pos = atoi(argv[2]);
return getPos(self,argv[0],pCon,pos);
} else if(strcmp(argv[1],"divideby") == 0){
if(argc < 3){
SCWrite(pCon,"ERROR: need a SICSdata to divide by",eError);
return 0;
}
return divideSicsData(self,pSics,pCon,argv[2]);
} else if(strcmp(argv[1],"copydata") == 0){
return copyData(self,pSics,pCon,argc, argv);
} else if(strcmp(argv[1],"putint") == 0){ } else if(strcmp(argv[1],"putint") == 0){
/*---------- putint */ /*---------- putint */
return putInt(self,argc-2,&argv[2],pCon, pSics); return putInt(self,argc-2,&argv[2],pCon, pSics);

View File

@ -40,4 +40,11 @@
void *pData, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
void clearSICSData(pSICSData self);
int getSICSDataInt(pSICSData self, int pos, int *value);
int getSICSDataFloat(pSICSData self, int pos, float *value);
int setSICSDataInt(pSICSData self, int pos, int value);
int setSICSDataFloat(pSICSData self, int pos, float value);
#endif #endif

View File

@ -6,6 +6,8 @@ sources such as histogram memories or scans. Data assembled in this
way, for instance through scripts, can then be forwarded to clients way, for instance through scripts, can then be forwarded to clients
either in UUencoded form or as a zipped array. either in UUencoded form or as a zipped array.
WARNING: this code only works right when integers and floats are of the same size!
In a later stage this may be extended to support selected mathematical In a later stage this may be extended to support selected mathematical
operations as well. In another stage this may supersede the uuget and operations as well. In another stage this may supersede the uuget and
zipget methods in the scan, histogram memory and specialized status zipget methods in the scan, histogram memory and specialized status
@ -48,6 +50,13 @@ This object exports the following functions:
int SICSDataAction(SConnection *pCon, SicsInterp *pSics, int SICSDataAction(SConnection *pCon, SicsInterp *pSics,
void *pData, void *pData,
int argc, char *argv[]); int argc, char *argv[]);
void clearSICSData(pSICSData self);
int getSICSDataInt(pSICSData self, int pos, int *value);
int getSICSDataFloat(pSICSData self, int pos, float *value);
int setSICSDataInt(pSICSData self, int pos, int value);
int setSICSDataFloat(pSICSData self, int pos, float value);
@} @}
\begin{description} \begin{description}
\item[getSICSDataPointer] returns a pointer to the first element of \item[getSICSDataPointer] returns a pointer to the first element of

513
sicshdbadapter.c Normal file
View File

@ -0,0 +1,513 @@
/*
* Experience has shown that integrating existing SICS objects into the
* Hierarchical Parameter Database (Hdb) is a difficult task without reworking
* the complete SICS object model. Rather, it seems easier to adapt some
* critical objects to the Hdb with some glue code. Following the facade or
* adapter design pattern. This is the purpose of this module. For the moment
* the external interface is only an interpreter function which will be used to
* install suitable SICS objects into the Hdb tree and generates the necessary
* adapters internally. This code can be used to adapt to:
* - motors
* - the data segment of histogram memories
*
* copyright: see file COPYRIGHT
*
* Mark Koennecke, November 2006
*/
#include <stdlib.h>
#include <assert.h>
#include <sics.h>
#include "stptok.h"
#include "motor.h"
#include "HistMem.h"
#include "sicsvar.h"
#include "sicshipadaba.h"
#include "sicshdbadapter.h"
#define PRIVNAM "priv"
/*==================== support code ====================================*/
static void AddPrivProperty(pHdb node, int priv){
char pPriv[80];
switch(priv){
case usInternal:
strcpy(pPriv,"internal");
break;
case usMugger:
strcpy(pPriv,"manager");
break;
case usUser:
strcpy(pPriv,"user");
break;
case usSpy:
strcpy(pPriv,"spy");
break;
default:
assert(0);
break;
}
SetHdbProperty(node,PRIVNAM,pPriv);
}
/*=================== motor code =======================================*/
static int MoveCallback(int iEvent, void *eventData, void *userData,
commandContext cc){
MotCallback *motData = (MotCallback *)eventData;
pHdb motor = (pHdb)userData;
pHdb pos = NULL;
if(iEvent == MOTDRIVE && motData != NULL && motor != NULL){
UpdateHipadabaPar(motor,MakeHdbFloat((double)motData->fVal)
,NULL);
pos = GetHipadabaNode(motor,"position");
if(pos != NULL){
UpdateHipadabaPar(pos,MakeHdbFloat((double)motData->fVal)
,NULL);
}
}
return 1;
}
/*---------------------------------------------------------------------*/
static int MotorValueCallback(int iEvent, void *eventData, void *userData,
commandContext cc){
pHdb motor = (pHdb)userData;
pMotor pMot = (pMotor)eventData;
pHdb current = NULL;
float fVal;
/*
* as setting some motor parameters might cause other motor
* parametes to change too, I opt for the cheap solution to check
* them all.
*/
if(iEvent == HDBVAL && motor != NULL && pMot != NULL){
current = motor->child;
while(current != NULL){
MotorGetPar(pMot,current->name,&fVal);
if(fVal != current->value.v.doubleValue) {
UpdateHipadabaPar(current,MakeHdbFloat((double)fVal),NULL);
}
current = current->next;
}
}
return 1;
}
/*---------------------------------------------------------------------*/
static int MotorParSetCallback(void *userData, void *callData,
pHdb currentNode, hdbValue v){
pMotor pMot = (pMotor)userData;
SConnection *pCon = (SConnection *)callData;
int status;
assert(pMot != NULL && pCon != NULL);
status = MotorSetPar(pMot,pCon,currentNode->name, (float)v.v.doubleValue);
return status;
}
/*----------------------------------------------------------------------*/
static int MotorParGetCallback(void *userData, void *callData,
pHdb currentNode, hdbValue v){
pMotor pMot = (pMotor)userData;
float fVal;
int status;
assert(pMot != NULL);
status = MotorGetPar(pMot,currentNode->name,&fVal);
currentNode->value.v.doubleValue = fVal;
return status;
}
/*---------------------------------------------------------------------*/
static pHdb MakeMotParNode(char *name, pMotor pMot){
pHdb node = NULL;
pHdbCallback pCall = NULL;
node = MakeHipadabaNode(name, HIPFLOAT, 1);
if(node != NULL) {
pCall = MakeHipadabaCallback(MotorParSetCallback,pMot,NULL,-1,-1);
if(pCall == NULL){
return NULL;
}
AppendHipadabaCallback(node,HCBSET,pCall);
pCall = MakeHipadabaCallback(MotorParGetCallback,pMot,NULL,-1,-1);
if(pCall == NULL){
return NULL;
}
AppendHipadabaCallback(node,HCBREAD,pCall);
}
return node;
}
/*---------------------------------------------------------------------*/
static int AddStdMotorPar(pHdb motorNode, pMotor pMot){
int i;
pHdb parNode = NULL;
char *addPar[] = {"target",
"hardlowerlim",
"hardupperlim",
NULL};
i = 0;
while(addPar[i] != NULL){
parNode = MakeMotParNode(addPar[i],pMot);
SetHdbProperty(parNode,PRIVNAM,"internal");
if(parNode == NULL){
return 0;
}
AddHipadabaChild(motorNode,parNode, NULL);
i++;
}
/*
* Add the parameters in the obpar array
*/
for(i = 0; i < MOTOBPARLENGTH; i++){
parNode = MakeMotParNode(pMot->ParArray[i].name,pMot);
if(parNode == NULL){
return 0;
}
AddHipadabaChild(motorNode,parNode, NULL);
AddPrivProperty(parNode,pMot->ParArray[i].iCode);
}
return 1;
}
/*--------------------------------------------------------------------------*/
static char *getDriverParList(MotorDriver *pDriv){
SConnection *pCon = NULL;
pDynString list = NULL;
char *listData = NULL;
if(pDriv->ListDriverPar != NULL){
pCon = SCCreateDummyConnection(pServ->pSics);
if(pCon == NULL){
return NULL;
}
SCStartBuffering(pCon);
pDriv->ListDriverPar(pDriv,"test.", pCon);
list = SCEndBuffering(pCon);
if(list != NULL){
listData = strdup(GetCharArray(list));
SCDeleteConnection(pCon);
} else {
listData = NULL;
}
return listData;
}
return NULL;
}
/*--------------------------------------------------------------------------*/
extern char *trim(char *str);
/*--------------------------------------------------------------------------*/
static char *extractName(char *line){
char *name = NULL, *pEnd = NULL;
name = strchr(line,'.');
assert(name != NULL);
while(*name == '.'){
name++;
}
pEnd = strchr(name,'=');
assert(pEnd != NULL);
*pEnd = '\0';
return trim(name);
}
/*------------------------------------------------------------------------*/
static int CreateDriverParameters(pMotor pM, pHdb parent){
char *listPtr = NULL, line[80], *pPtr, *name;
pHdb node = NULL;
listPtr = getDriverParList(pM->pDriver);
if(listPtr == NULL){
/*
* no driver parameters
*/
return 1;
}
pPtr = listPtr;
while((pPtr = stptok(pPtr,line,79,"\n")) != NULL){
name = extractName(line);
node = MakeMotParNode(name,pM);
SetHdbProperty(node,PRIVNAM,"manager");
if(node != NULL){
AddHipadabaChild(parent,node,NULL);
}
}
free(listPtr);
return 1;
}
/*----------------------------------------------------------------------*/
static pHdb CreateMotorAdapter(char *name, pMotor pMot){
pHdb result = NULL;
commandContext comCom;
float access;
assert(pMot != NULL);
result = MakeSICSHdbDriv(name,usUser,pMot,HIPFLOAT);
if(result == NULL){
return NULL;
}
MotorGetPar(pMot,"accesscode",&access);
AddPrivProperty(result,(int)access);
SetHdbProperty(result,"type","drivable");
SetHdbProperty(result,"sicsdev",pMot->name);
/*
* We want to be notified when this motor drives around. Or
* its parameters change.
*/
strncpy(comCom.deviceID,name,255);
comCom.transID = -77;
RegisterCallback(pMot->pCall,comCom, MOTDRIVE, MoveCallback,
result,NULL);
RegisterCallback(pMot->pCall,comCom, HDBVAL, MotorValueCallback,
result,NULL);
if(!AddStdMotorPar(result,pMot)){
DeleteHipadabaNode(result,NULL);
return NULL;
}
if(!CreateDriverParameters(pMot,result)){
DeleteHipadabaNode(result,NULL);
return NULL;
}
result->protected = 1;
return result;
}
/*============== histogram memory ======================================*/
static long totalSum(int *data, int length){
long result = 0l;
int i;
if(data == NULL){
return 0;
}
for(i = 0; i < length; i++){
result += data[i];
}
return result;
}
/*----------------------------------------------------------------------*/
static int HMDataGetCallback(void *userData, void *callData,
pHdb currentNode, hdbValue v){
pHistMem pHM = (pHistMem)userData;
SConnection *pCon = (SConnection *)callData;
long sum1, sum2;
assert(pHM != NULL);
if(pCon == NULL){
return 0;
}
sum1 = totalSum(currentNode->value.v.intArray, currentNode->value.arrayLength);
currentNode->value.arrayLength = GetHistLength(pHM);
currentNode->value.v.intArray = (int *)GetHistogramPointer(pHM,pCon);
sum2 = totalSum(currentNode->value.v.intArray, currentNode->value.arrayLength);
if(sum1 != sum2){
UpdateHipadabaPar(currentNode,currentNode->value,NULL);
}
return 1;
}
/*----------------------------------------------------------------------*/
static pHdb MakeHMDataNode(pHistMem pHM, char *name){
pHdb node = NULL;
pHdbCallback pCall = NULL;
node = MakeHipadabaNode(name,HIPINTVARAR,2);
if(node == NULL){
return NULL;
}
pCall = MakeHipadabaCallback(HMDataGetCallback,pHM,NULL,-1,-1);
if(pCall == NULL){
return NULL;
}
AppendHipadabaCallback(node,HCBREAD,pCall);
AppendHipadabaCallback(node,HCBSET,MakeReadOnlyCallback());
return node;
}
/*================ SICS Variable ======================================*/
static int SicsVarSetCallback(void *userData, void *callData,
pHdb currentNode, hdbValue v){
pSicsVariable pVar = (pSicsVariable)userData;
SConnection *pCon = (SConnection *)callData;
int userRights = usMugger;
assert(pVar != NULL);
if(pCon != NULL){
userRights = SCGetRights(pCon);
}
switch(currentNode->value.dataType){
case HIPINT:
VarSetInt(pVar, v.v.intValue, userRights);
break;
case HIPFLOAT:
VarSetFloat(pVar, (float)v.v.doubleValue, userRights);
break;
case HIPTEXT:
VarSetText(pVar, v.v.text, userRights);
break;
}
return 1;
}
/*----------------------------------------------------------------------*/
static int ValueCallback(int iEvent, void *eventData, void *userData,
commandContext cc){
pSicsVariable pVar = (pSicsVariable)eventData;
pHdb node = (pHdb)userData;
hdbValue v;
if(iEvent == VALUECHANGE && pVar != NULL && node != NULL){
switch(pVar->eType){
case veInt:
v = MakeHdbInt(pVar->iVal);
break;
case veFloat:
v = MakeHdbFloat((double)pVar->fVal);
break;
case veText:
v = MakeHdbText(pVar->text);
break;
}
UpdateHipadabaPar(node,v,NULL);
}
return 1;
}
/*----------------------------------------------------------------------*/
static pHdb MakeSicsVarNode(pSicsVariable pVar, char *name){
pHdb node = NULL;
pHdbCallback pCall = NULL;
commandContext comCom;
int type;
switch(pVar->eType){
case veInt:
type = HIPINT;
break;
case veFloat:
type = HIPFLOAT;
break;
case veText:
type = HIPTEXT;
break;
}
node = MakeHipadabaNode(name,type,1);
if(node == NULL){
return NULL;
}
if(pVar->iLock == 1) {
AddPrivProperty(node,usInternal);
} else {
AddPrivProperty(node,pVar->iAccessCode);
}
pCall = MakeHipadabaCallback(SicsVarSetCallback,pVar,NULL,-1,-1);
if(pCall == NULL){
return NULL;
}
strncpy(comCom.deviceID,name,255);
comCom.transID = -77;
AppendHipadabaCallback(node,HCBSET,pCall);
RegisterCallback(pVar->pCall,comCom, VALUECHANGE, ValueCallback,
node,NULL);
node->protected = 1;
return node;
}
/*============== interpreter function ==================================*/
int SICSHdbAdapter(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]){
pHdb root = NULL;
pHdb path = NULL;
pHdb node = NULL;
pMotor pMot = NULL;
pHistMem pHM = NULL;
CommandList *pCom = NULL;
pIDrivable pDriv = NULL;
pSicsVariable pVar = NULL;
char buffer[512];
root = GetHipadabaRoot();
assert(root != NULL);
if(!SCMatchRights(pCon,usMugger)){
return 0;
}
if(argc < 4) {
SCWrite(pCon,"ERROR: Insufficient number of arguments",eError);
return 0;
}
path = GetHipadabaNode(root,argv[1]);
if(path == NULL){
SCWrite(pCon,"ERROR: path to attach object too not found",eError);
return 0;
}
/*
* look for motors
*/
pMot = (pMotor)FindCommandData(pSics,argv[2],"Motor");
if(pMot != NULL){
node = CreateMotorAdapter(argv[3],pMot);
if(node == NULL){
SCWrite(pCon,"ERROR: out of memory creating motor node",eError);
return 0;
}
AddHipadabaChild(path,node,pCon);
SCSendOK(pCon);
return 1;
}
/*
* look for drivables
*/
pDriv = FindDrivable(pSics,argv[2]);
pCom = FindCommand(pSics,argv[2]);
if(pDriv != NULL && pCom != NULL && pCom->pData != NULL){
node = MakeSICSHdbDriv(argv[3],usUser,pCom->pData,HIPFLOAT);
if(node == NULL){
SCWrite(pCon,"ERROR: out of memory creating drivable node",eError);
return 0;
}
SetHdbProperty(node,PRIVNAM,"user");
SetHdbProperty(node,"type","drivable");
SetHdbProperty(node,"sicsdev",argv[2]);
AddHipadabaChild(path,node,pCon);
SCSendOK(pCon);
return 1;
}
/**
* look for SICS Variables
*/
pVar = (pSicsVariable)FindCommandData(pSics,argv[2],"SicsVariable");
if(pVar != NULL){
node = MakeSicsVarNode(pVar,argv[3]);
if(node == NULL){
SCWrite(pCon,"ERROR: out of memory creating SICS variable node",
eError);
return 0;
}
AddHipadabaChild(path,node,pCon);
SCSendOK(pCon);
return 1;
}
/*
* look for histogram memories
*/
pHM = (pHistMem)FindCommandData(pSics,argv[2],"HistMem");
if(pHM != NULL){
node = MakeHMDataNode(pHM,argv[3]);
if(node == NULL){
SCWrite(pCon,"ERROR: out of memory creating HM node",eError);
return 0;
}
AddHipadabaChild(path,node,pCon);
SCSendOK(pCon);
return 1;
}
snprintf(buffer,511,
"ERROR: attaching this type of object: %s at %s not implemented",
argv[2], argv[1]);
SCWrite(pCon,buffer,eError);
return 0;
}

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