/* * 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 #include #include #include "stptok.h" #include "motor.h" #include "HistMem.h" #include "sicsvar.h" #include "sicshipadaba.h" #include "sicshdbadapter.h" #define PRIVNAM "privilege" /*==================== support code ====================================*/ static void AddPrivProperty(pHdb node, int priv){ char pPriv[80]; switch(priv){ case usInternal: strcpy(pPriv,"READ_ONLY"); 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; hdbValue v; 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); 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); 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; }