From 0fd55c2c3974a6c25e257b873b049b481cf27645 Mon Sep 17 00:00:00 2001 From: koennecke Date: Mon, 14 Jul 2008 07:22:41 +0000 Subject: [PATCH] - More debugging of scriptcontext, mostly working now - Created driveable SICSobj for standalone and as an adapter --- ascon.c | 23 +++- devser.c | 9 +- fomerge.c | 48 ++++--- ifile.c | 3 +- make_gen | 4 +- sctdriveadapter.c | 4 + sctdriveobj.c | 337 ++++++++++++++++++++++++++++++++++++++++++++++ sicsobj.c | 35 ++++- sicsobj.h | 3 + sllinux_def | 2 +- 10 files changed, 433 insertions(+), 35 deletions(-) create mode 100644 sctdriveobj.c diff --git a/ascon.c b/ascon.c index e4a8ab53..3fb2fe23 100644 --- a/ascon.c +++ b/ascon.c @@ -117,10 +117,16 @@ static void AsconConnect(Ascon *a) { fcntl(a->fd, F_SETFL, oldopts | O_NONBLOCK); ret = connect(a->fd, (struct sockaddr *)&adr, sizeof(struct sockaddr_in)); if (ret < 0) { - if (errno != EINPROGRESS) { - AsconError(a, "connect failed:", errno); - return; - } + switch(errno) { + case EINPROGRESS: + case EALREADY: + case EISCONN: + a->state = AsconConnecting; + break; + default: + AsconError(a, "connect failed:", errno); + return; + } } a->state = AsconConnecting; return; @@ -289,6 +295,9 @@ int AsconStdHandler(Ascon *a) { DynStringConcat(a->wrBuffer, a->sendTerminator); a->wrPos = 0; a->state = AsconWriting; + if(strstr(GetCharArray(a->wrBuffer),"@@NOSEND@@") != NULL){ + a->state = AsconWriteDone; + } break; case AsconWriting: AsconReadGarbage(a->fd); @@ -296,6 +305,10 @@ int AsconStdHandler(Ascon *a) { ret = AsconWriteChars(a->fd, GetCharArray(a->wrBuffer) + a->wrPos, l); if (ret < 0) { AsconError(a, "send failed:", errno); + /* + * Ooops: which state shall we go to after a write fail? + * This seems to retry. + */ } else { a->wrPos += ret; if (a->wrPos >= GetDynStringLength(a->wrBuffer)) { @@ -476,6 +489,8 @@ AsconStatus AsconTask(Ascon *a) { now = DoubleTime(); if (now > a->lastReconnect + a->reconnectInterval) { a->lastReconnect = now; + close(a->fd); + a->fd = -1; a->state = AsconConnectStart; } } diff --git a/devser.c b/devser.c index 3afbc848..af7da49b 100644 --- a/devser.c +++ b/devser.c @@ -74,6 +74,7 @@ DevAction *DevNextAction(DevSer *devser) { double now; SchedHeader *header; + devser->current = NULL; if (devser->actions) { prio = devser->actions->prio; @@ -125,6 +126,7 @@ int DevQueueTask(void *ds) { if (action == NULL) { action = DevNextAction(devser); } + while (action != NULL) { status = AsconTask(devser->asyncConn); if (status == AsconFailure) { @@ -226,7 +228,7 @@ void DevQueue(DevSer *devser, void *actionData, DevPrio prio, ptr2Last = &devser->actions; for (action = devser->actions; action != NULL && action->prio >= prio; action = action->next) { if (action->hdl == hdl && matchFunc(actionData, action->data)) { - return; /* there is already an identic action */ + return; /* there is already an identical action */ } ptr2Last = &action->next; } @@ -241,7 +243,7 @@ int DevUnschedule(DevSer *devser, void *actionData, DevAction **ptr2Last = NULL; DevAction *action = NULL; int cnt=0; - + /* scan through all headers */ for (header = devser->headers; header != NULL; header = header->next) { ptr2Last = &header->actions; @@ -279,7 +281,7 @@ int DevSchedule(DevSer *devser, void *actionData, DevAction **ptr2Last = NULL; DevAction *newAction; int ret; - + if (prio <= NullPRIO) prio = NullPRIO + 1; if (prio >= NumberOfPRIO) prio = NumberOfPRIO - 1; ret = DevUnschedule(devser, actionData, hdl, matchFunc); @@ -330,6 +332,7 @@ int DevRemoveAction(DevSer *devser, void *actionData) { DevAction *action = NULL; int cnt=0; + /* Remove current action, if matched. If a reply is pending, the next action will get the reply. But as in the inital state no reply is expected, this should not harm. */ action = devser->current; diff --git a/fomerge.c b/fomerge.c index df88dc38..b6dc9d20 100644 --- a/fomerge.c +++ b/fomerge.c @@ -689,10 +689,8 @@ static int TOFLambda(SicsInterp *pSics, SConnection *pCon, return 1; } /*---------------------------------------------------------------------*/ -static int putElastic(SicsInterp *pSics, SConnection *pCon, - pNXScript pNexus, char *alias, float fElastic) +static float calcElastic(SicsInterp *pSics, SConnection *pCon) { - int status, iTime, iDet, i; const float *fTimeBin = NULL; int *sum = NULL; @@ -706,7 +704,7 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon, SCWrite(pCon, "ERROR: need middle detector bank for elastic peak calculation", eError); - return NX_ERROR; + return -1.; } fTimeBin = GetHistTimeBin(pMem,&iTime); iDet = getFMdim(MIDDLE); @@ -715,7 +713,7 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon, { SCWrite(pCon,"ERROR: out of memory calculating elastic peak position", eError); - return NX_ERROR; + return -1; } if(fitter == NULL) { @@ -723,7 +721,7 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon, if(!fitter) { SCWrite(pCon,"ERROR: cannot allocate fitting structure",eError); - return NX_ERROR; + return -1.; } } /* @@ -734,7 +732,7 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon, { SCWrite(pCon,"ERROR: out of memory in putElastic",eError); free(sum); - return NX_ERROR; + return -1.; } for(i = 0; i < iTime; i++) { @@ -743,20 +741,26 @@ static int putElastic(SicsInterp *pSics, SConnection *pCon, status = CalculateFitFromData(fitter,(float *)fTimeBin,lSum,iTime); free(lSum); GetFitResults(fitter,&fCenter,&fStdDev,&fFWHM,&fVal); - fVal = fCenter - fElastic; - if(fVal < 0.) - fVal = - fVal; - /* bad value, leave at theoretical value */ - if(fVal < 10.) - { - fElastic = fCenter; - } free(sum); - - status = NXDputalias(pNexus->fileHandle, pNexus->dictHandle,alias, - &fElastic); - return status; + return fCenter; +} +/*---------------------------------------------------------------------*/ +#define ABS(x) (x < 0 ? -(x) : (x)) +static int putElastic(SicsInterp *pSics, SConnection *pCon, + pNXScript pNexus, char *alias, float fElastic) +{ + float fCalc; + int status; + + fCalc = calcElastic(pSics,pCon); + if(ABS(fElastic -fCalc) < 20) { + fElastic = fCalc; + } + + status = NXDputalias(pNexus->fileHandle, pNexus->dictHandle,alias, + &fElastic); + return status; } /*----------------------------------------------------------------------*/ static int FMputTTH(SConnection *pCon, int argc, char *argv[]){ @@ -909,6 +913,7 @@ static int FMcopyMergedSum(SConnection *pCon, int argc, char *argv[]){ focusmerge putsum nxscriptmod bankname alias focusmerge putelastic nxscriptmod alias theoelastic focusmerge toflambda + focusmerge elastic nxscriptmod = name of the nxscript module used for writing, must be open alias = The alias under which to write the data item @@ -944,6 +949,11 @@ int FocusMergeAction(SConnection *pCon, SicsInterp *pSics, void *pData, if(strcmp(argv[1],"toflambda") == 0){ return TOFLambda(pSics, pCon,argc,argv); } + if(strcmp(argv[1],"elastic") == 0){ + fElastic = calcElastic(pSics,pCon); + SCPrintf(pCon,eValue,"tofelastic = %f", fElastic); + return 1; + } if(strcmp(argv[1],"puttwotheta") == 0) { diff --git a/ifile.c b/ifile.c index 458d41b0..04640f5e 100644 --- a/ifile.c +++ b/ifile.c @@ -49,11 +49,12 @@ static IPair *CreateNewEntry(char *name, char *val, IPair *pN) { - IPair *pRes; + IPair *pRes = NULL; pRes = (IPair *)malloc(sizeof(IPair)); if(!pRes) return NULL; + memset(pRes,0,sizeof(IPair)); if(name) pRes->name = strdup(name); if(val) diff --git a/make_gen b/make_gen index 613c6f1e..52421db2 100644 --- a/make_gen +++ b/make_gen @@ -37,7 +37,7 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ sicshdbadapter.o polldriv.o sicspoll.o statemon.o hmslave.o \ nwatch.o asyncqueue.o asyncprotocol.o sicsobj.o \ nxcopy.o nxinterhelper.o nxinter_wrap.o genericcontroller.o nxstack.o \ - sctdriveadapter.o + sctdriveadapter.o sctdriveobj.o MOTOROBJ = motor.o simdriv.o COUNTEROBJ = countdriv.o simcter.o counter.o @@ -60,7 +60,7 @@ full: purge all SICServer: $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) \ $(VELOOBJ) $(DIFIL) $(EXTRA) \ $(SUBLIBS) - $(CC) -g -o SICServer \ + $(CC) -g -pg -o SICServer \ $(SOBJ) $(MOTOROBJ) $(COUNTEROBJ) \ $(VELOOBJ) $(DIFOBJ) $(EXTRA) $(LIBS) diff --git a/sctdriveadapter.c b/sctdriveadapter.c index 6b65700e..6b496fee 100644 --- a/sctdriveadapter.c +++ b/sctdriveadapter.c @@ -312,7 +312,11 @@ int SctMakeDriveAdapter(SConnection *pCon, SicsInterp *pSics, void *object, return 1; } /*---------------------------------------------------------------*/ +int SctMakeDriveObject(SConnection *pCon, SicsInterp *pSics, void *object, + int argc, char *argv[]); + void SctDriveInit(void) { AddCmd("makesctdrive", SctMakeDriveAdapter); AddCmd("dynsctdrive", SctMakeDriveAdapter); + AddCmd("makesctdriveobj",SctMakeDriveObject); } diff --git a/sctdriveobj.c b/sctdriveobj.c new file mode 100644 index 00000000..e747a863 --- /dev/null +++ b/sctdriveobj.c @@ -0,0 +1,337 @@ +/** + * This is a base class for any drivable object which uses the new + * scriptcontext to control the actual driving operation. This can also + * serve as a drivable adapter to nodes in other objects. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, June-July 2008 + */ +#include +#include +#include +#include +#include + +typedef struct { + pIDrivable pDriv; + SctController *c; + int doNotKillNode; +} DrivObjPriv, *pDrivObjPriv; +/*---------------------------------------------------------------*/ +static void *SCTDRIVGetInterface(void *data, int iD){ + pSICSOBJ self = NULL; + pDrivObjPriv pPriv; + + self = (pSICSOBJ)data; + pPriv = (pDrivObjPriv)self->pPrivate; + if(self != NULL && pPriv != NULL && iD == DRIVEID){ + if (self->objectNode == NULL) return NULL; + return pPriv->pDriv; + } else { + return NULL; + } + return NULL; +} +/*---------------------------------------------------------------- + This routine can return either OKOK or HWFault when thing + go wrong. However, the return value of Halt is usually ignored! +------------------------------------------------------------------*/ +static int SCTDRIVHalt(void *data) { + pSICSOBJ self = NULL; + pDrivObjPriv pPriv; + char dummy[16]; + + self = (pSICSOBJ)data; + pPriv = (pDrivObjPriv)self->pPrivate; + if (GetHdbProperty(self->objectNode,"halt", dummy, sizeof dummy)) { + SctQueueNode(pPriv->c, self->objectNode, HaltPRIO, "halt", NULL); + } else if (GetHdbProperty(self->objectNode, "status", dummy, sizeof dummy)) { + SetHdbProperty(self->objectNode, "status", "idle"); + } + return OKOK; +} +/*---------------------------------------------------------------- + This routine can return either 1 or 0. 1 means the position can + be reached, 0 NOT + If 0, error shall contain up to errlen characters of information + about which limit was violated +------------------------------------------------------------------*/ +static int SCTDRIVCheckLimits(void *data, float val, + char *error, int errlen){ + pSICSOBJ self = NULL; + pDrivObjPriv pPriv; + char script[1024]; + int status; + Tcl_Interp *pTcl = NULL; + char *result; + + self = (pSICSOBJ)data; + pPriv = (pDrivObjPriv)self->pPrivate; + snprintf(script,1024,"%f", val); + SetHdbProperty(self->objectNode,"target", script); + if(GetHdbProperty(self->objectNode,"checklimits",script,1024)){ + status = SctCallInContext(pServ->dummyCon, script, + self->objectNode, pPriv->c, &result); + if(SctVerbose(pPriv->c)){ + SCPrintf(pServ->dummyCon, eWarning, "script %s called with result %s\n ", + script, result); + } + if(status == 0){ + strncpy(error,result,errlen); + return 0; + } + } + return 1; +} +/*---------------------------------------------------------------- + This routine can return 0 when a limit problem occurred + OKOK when the motor was successfully started + HWFault when a problem occured starting the device + Possible errors shall be printed to pCon + For real motors, this is supposed to try at least three times + to start the motor in question + val is the value to drive the motor too +------------------------------------------------------------------*/ +static long SCTDRIVSetValue(void *data, SConnection *pCon, float val){ + pSICSOBJ self = NULL; + pDrivObjPriv pPriv; + int status; + hdbValue v; + + self = (pSICSOBJ)data; + pPriv = (pDrivObjPriv)self->pPrivate; + + v.dataType = HIPFLOAT; + v.v.doubleValue = (double)val; + SetHdbProperty(self->objectNode,"writestatus", "start"); + status = SetHipadabaPar(self->objectNode, v, pCon); + if(status == 1){ + return OKOK; + } else { + return HWFault; + } +} +/*---------------------------------------------------------------- + Checks the status of a running motor. Possible return values + HWBusy The motor is still running + OKOK or HWIdle when the motor finished driving + HWFault when a hardware problem ocurred + HWPosFault when the hardware cannot reach a position + Errors are duly to be printed to pCon + For real motors CheckStatus again shall try hard to fix any + issues with the motor +------------------------------------------------------------------*/ +static int SCTDRIVCheckStatus(void *data, SConnection *pCon){ + pSICSOBJ self = NULL; + pDrivObjPriv pPriv; + char script[1024]; + int status; + Tcl_Interp *pTcl = NULL; + char *result; + SConnection *con; + + self = (pSICSOBJ)data; + pPriv = (pDrivObjPriv)self->pPrivate; + + /* + * check if the write command has gone through + */ + if(GetHdbProperty(self->objectNode,"writestatus", script,1024)){ + if(strcmp(script,"start") == 0){ + return HWBusy; + } + } + + /* + * run the checkstatus script + */ + if(!GetHdbProperty(self->objectNode,"checkstatus",script,1024)){ + if (!GetHdbProperty(self->objectNode,"status",script,1024)){ + SCWrite(pCon, + "ERROR: configuration problem: no checkstatus script!", eError); + return HWFault; + } + result = script; + } else { + status = SctCallInContext(pCon,script, self->objectNode, + pPriv->c, &result); + if (status == 0) { + SCPrintf(pCon,eError," script %s returned %s", + script, result); + return HWFault; + } + if(SctVerbose(pPriv->c)){ + SCPrintf(pCon,eError," script %s returned %s", + script, result); + } + } + if(strstr(result,"busy") != NULL){ + return HWBusy; + } else if(strstr(result,"posfault") != NULL){ + return HWPosFault; + } else if(strstr(result,"fault") != NULL){ + return HWFault; + } else if(strstr(result,"idle") != NULL){ + return HWIdle; + } else { + SCPrintf(pCon,eError, + "ERROR: invalid status code %s returned from checkstatus script", + result); + return HWFault; + } + return HWFault; +} +/*---------------------------------------------------------------- + GetValue is supposed to read a motor position + On errors, -99999999.99 is returned and messages printed to pCon +------------------------------------------------------------------*/ +static float SCTDRIVGetValue(void *data, SConnection *pCon){ + pSICSOBJ self = NULL; + pDrivObjPriv pPriv; + float val = -99999999.99; + int status; + char error[256]; + hdbValue v; + + self = (pSICSOBJ)data; + pPriv = (pDrivObjPriv)self->pPrivate; + if(GetHdbProperty(self->objectNode,"geterror", error, 256)){ + SCWrite(pCon,error, eError); + return val; + } + return (float)self->objectNode->value.v.doubleValue; +} +/*-----------------------------------------------------------------*/ +void AssignSctDrive(pIDrivable pDriv){ + pDriv->Halt = SCTDRIVHalt; + pDriv->CheckLimits = SCTDRIVCheckLimits; + pDriv->SetValue = SCTDRIVSetValue; + pDriv->CheckStatus = SCTDRIVCheckStatus; + pDriv->GetValue = SCTDRIVGetValue; +} +/*---------------------------------------------------------------------------*/ +static void KillDriveOBJ(void *data){ + pSICSOBJ self = (pSICSOBJ)data; + pDrivObjPriv pPriv; + + if(self == NULL){ + return; + } + + pPriv = (pDrivObjPriv)self->pPrivate; + if(pPriv->doNotKillNode && self->pDes != NULL){ + if(self->pDes->name) free(self->pDes->name); + if(self->pDes->pKeys) IFDeleteOptions(self->pDes->pKeys); + free(self->pDes); + } else { + DeleteDescriptor(self->pDes); /* kill descriptor including node */ + } + if(self->KillPrivate != NULL && self->pPrivate != NULL){ + self->KillPrivate(self->pPrivate); + } + RemoveHdbNodeFromParent(self->objectNode, pServ->dummyCon); + free(self); +} +/*-----------------------------------------------------------------------------*/ +pSICSOBJ MakeSctDriveObj(pHdb node, char *class, SctController *c){ + pSICSOBJ pNew = NULL; + pDrivObjPriv pPriv = NULL; + hdbValue val; + + pNew = (pSICSOBJ)malloc(sizeof(SICSOBJ)); + pPriv = (pDrivObjPriv)malloc(sizeof(DrivObjPriv)); + if(pNew == NULL || pPriv == NULL){ + return NULL; + } + memset(pNew,0,sizeof(SICSOBJ)); + memset(pPriv,0,sizeof(DrivObjPriv)); + + pNew->pDes = CreateDescriptor(class); + pPriv->pDriv = CreateDrivableInterface(); + if(pNew->pDes == NULL || pPriv->pDriv == NULL){ + free(pNew); + free(pPriv); + return(NULL); + } + pNew->objectNode = node; + AssignSctDrive(pPriv->pDriv); + pPriv->c = c; + pNew->pDes->parNode = pNew->objectNode; + pNew->pDes->GetInterface = SCTDRIVGetInterface; + pNew->pPrivate = pPriv; + pNew->KillPrivate = DefaultKill; + return pNew; +} +/*-------------------------------------------------------------------------- + * This actually has two syntaxes: + * makesctdrive name path-to-existing-node class SctController + * makesctdrive name type priv class SctController + *--------------------------------------------------------------------------*/ +int SctMakeDriveObject(SConnection *pCon, SicsInterp *pSics, void *object, + int argc, char *argv[]) { + pHdb node = NULL; + pDrivObjPriv pPriv = NULL; + pSICSOBJ pNew = NULL; + pSICSOBJ pSct = NULL; + SctController *c = NULL; + int priv, type, status; + hdbValue val; + + if(argc < 5){ + SCWrite(pCon,"ERROR: not enough arguments to SctMakeDriveObject", eError); + return 0; + } + + node = FindHdbNode(NULL,argv[2], pCon); + if(node != NULL){ + pSct = FindCommandData(pSics,argv[4], "SctController"); + if(pSct == NULL){ + SCPrintf(pCon,eError, "ERROR: SctController %s not found", argv[4]); + return 0; + } + c = (SctController *)pSct->pPrivate; + pNew = MakeSctDriveObj(node,argv[3],c); + pPriv = (pDrivObjPriv)pNew->pPrivate; + pPriv->doNotKillNode = 1; /* the node is owned by someone else*/ + } else { + /* convert privilege */ + priv = decodeSICSPriv(argv[3]); + /* convert datatype */ + strtolower(argv[4]); + type = convertHdbType(argv[2]); + if (type == HIPNONE) { + node = MakeHipadabaNode(argv[1], HIPNONE, 1); + } else { + val = makeHdbValue(type,0); + node = MakeSICSHdbPar(argv[1], priv, val); + ReleaseHdbValue(&val); + } + if(node == NULL){ + SCWrite(pCon,"ERROR: node creation failed", eError); + return 0; + } + c = FindCommandData(pSics,argv[5], "SctController"); + if(c == NULL){ + SCPrintf(pCon,eError, "ERROR: SctController %s not found", argv[4]); + return 0; + } + pNew = MakeSctDriveObj(node,argv[3],c); + } + if(pNew == NULL){ + SCWrite(pCon,"ERROR: failed to create drive object", eError); + return 0; + } + status = AddCommand(pSics, + argv[1], + InterInvokeSICSOBJ, + KillDriveOBJ, + pNew); + if(status != 1){ + KillSICSOBJ(pNew); + SCPrintf(pCon,eError,"ERROR: failed create duplicate command %s", argv[1]); + return 0; + } + return 1; +} + diff --git a/sicsobj.c b/sicsobj.c index 14a5260e..0eaabcdd 100644 --- a/sicsobj.c +++ b/sicsobj.c @@ -18,7 +18,7 @@ extern int decodeSICSPriv(char *txt); /* from access.c */ /*--------------------------------------------------------------------------*/ -static void DefaultKill(void *data){ +void DefaultKill(void *data){ return; } /*---------------------------------------------------------------------------*/ @@ -209,22 +209,47 @@ static int MakeScriptFunc(pSICSOBJ self, SConnection *pCon, return 1; } /*---------------------------------------------------------------------------*/ +static int isNodePrintable(pHdb node){ + switch(node->value.dataType){ + case HIPNONE: + case HIPFUNC: + return 0; + default: + return 1; + } +} +/*---------------------------------------------------------------------------*/ int InvokeSICSOBJ(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]){ pSICSOBJ self = NULL; int status; pHdb parNode; char buffer[132]; + hdbValue data; + pDynString parData; self = (pSICSOBJ)pData; assert(self != NULL); - if(argc < 2){ - SCWrite(pCon,"ERROR: Nothing to process",eError); - return -1; - } if (argc == 1) { parNode = self->objectNode; + if(parNode != NULL && isNodePrintable(parNode) ){ + status = GetHipadabaPar(parNode,&data,pCon); + if(status != 1){ + return 0; + } + parData = formatValue(data, parNode); + if(parData == NULL){ + SCWrite(pCon,"ERROR: failed to format data", eError); + return 0; + } + SCPrintf(pCon,eValue,"%s = %s", argv[0], GetCharArray(parData)); + DeleteDynString(parData); + return 1; + } else { + SCWrite(pCon,"ERROR: nothing to print", eError); + return 0; + } } else { parNode = GetHipadabaNode(self->objectNode,argv[1]); } diff --git a/sicsobj.h b/sicsobj.h index 38461a39..a095d52a 100644 --- a/sicsobj.h +++ b/sicsobj.h @@ -28,6 +28,9 @@ typedef int (*SICSOBJFunc)(pSICSOBJ self, SConnection *pCon, pSICSOBJ MakeSICSOBJ(char *name, char *class); pSICSOBJ MakeSICSOBJv(char *name, char *class, int type, int priv); void KillSICSOBJ(void *data); +void DefaultKill(void *data); + + /** * This creates a new SICS object and installs it in the interpreter. It returns * the newly created SICS object such that the caller can continue diff --git a/sllinux_def b/sllinux_def index 570bc1e6..fdd1cc2a 100644 --- a/sllinux_def +++ b/sllinux_def @@ -6,7 +6,7 @@ #DFORTIFY= -DFORTIFY #FORTIFYOBJ= fortify.o strdup.o -#DFORTIFY= -p +DFORTIFY= -pg MFLAGS=-f makefile_linux$(DUMMY)