514 lines
15 KiB
C
514 lines
15 KiB
C
/*
|
|
* 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 "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;
|
|
|
|
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;
|
|
}
|