- Scriptcontext debugged to be working
- Added a drivable adapter to scriptcontext nodes - Added subsampling to simulated histograms (and as a general option) in order to support Gumtree testing.
This commit is contained in:
266
sctdriveadapter.c
Normal file
266
sctdriveadapter.c
Normal file
@ -0,0 +1,266 @@
|
||||
/**
|
||||
* This is an adapter to a node under the control of the new
|
||||
* scriptcontext generic device model. This is a wrapper around
|
||||
* such a node which implements the drivable interface.
|
||||
*
|
||||
* Soem cooperation from the node is required: It has to provide
|
||||
* certain properties the value of which define scripts which
|
||||
* have to be called at various stages. These are:
|
||||
*
|
||||
* checklimits, for limits checking
|
||||
* checkstatus, for evaluating progress
|
||||
* halt , for halting things
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, June 2008
|
||||
* --------------------------------------------------------------*/
|
||||
#include <sics.h>
|
||||
#include <sicshipadaba.h>
|
||||
#include <devser.h>
|
||||
#include <tcl.h>
|
||||
#include <macro.h>
|
||||
#include <sicsobj.h>
|
||||
/*------------- Some things from scriptcontext.c ----------------*/
|
||||
typedef struct SctController SctController;
|
||||
typedef struct SctData SctData;
|
||||
SctData *SctQueueNode(SctController *controller, pHdb node,
|
||||
DevPrio prio, char *action);
|
||||
int SctCallInContext(SConnection *con, char *script, Hdb *node,
|
||||
SctController *controller, char **resPtr);
|
||||
/*---------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
pObjectDescriptor pDes;
|
||||
pIDrivable pDriv;
|
||||
pHdb node;
|
||||
SctController *c;
|
||||
}SctDrive, *pSctDrive;
|
||||
/*---------------------------------------------------------------*/
|
||||
static void *SCTDRIVGetInterface(void *data, int iD){
|
||||
pSctDrive self = NULL;
|
||||
|
||||
self = (pSctDrive)data;
|
||||
if(self != NULL && iD == DRIVEID){
|
||||
return self->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) {
|
||||
pSctDrive self = NULL;
|
||||
|
||||
self = (pSctDrive)data;
|
||||
SctQueueNode(self->c, self->node, HaltPRIO, "halt");
|
||||
/*
|
||||
* SctQueueNode returns a dynamically allocated SctData
|
||||
* structure. I am not sure if this is not really a memory
|
||||
* leak
|
||||
*/
|
||||
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){
|
||||
pSctDrive self = NULL;
|
||||
char script[1024];
|
||||
int status;
|
||||
Tcl_Interp *pTcl = NULL;
|
||||
char *result;
|
||||
|
||||
self = (pSctDrive)data;
|
||||
snprintf(script,1024,"%f", val);
|
||||
SetHdbProperty(self->node,"target", script);
|
||||
if(GetHdbProperty(self->node,"checklimits",script,1024)){
|
||||
status = SctCallInContext(pServ->dummyCon, script,
|
||||
self->node, self->c, &result);
|
||||
if(status == 0){
|
||||
strncpy(error,result,errlen);
|
||||
}
|
||||
}
|
||||
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){
|
||||
pSctDrive self = NULL;
|
||||
int status;
|
||||
hdbValue v;
|
||||
|
||||
self = (pSctDrive)data;
|
||||
v.dataType = HIPFLOAT;
|
||||
v.v.doubleValue = (double)val;
|
||||
status = SetHipadabaPar(self->node, 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){
|
||||
pSctDrive self = NULL;
|
||||
char script[1024];
|
||||
int status;
|
||||
Tcl_Interp *pTcl = NULL;
|
||||
char *result;
|
||||
|
||||
self = (pSctDrive)data;
|
||||
|
||||
if(GetHdbProperty(self->node,"checkstatus",script,1024)){
|
||||
status = SctCallInContext(pCon,script, self->node,
|
||||
self->c, &result);
|
||||
if(status == 1){
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
SCWrite(pCon,result, eError);
|
||||
return HWFault;
|
||||
}
|
||||
} else {
|
||||
SCWrite(pCon,
|
||||
"ERROR: configuration problem: no checkstatus script!", eError);
|
||||
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){
|
||||
pSctDrive self = NULL;
|
||||
float val = -99999999.99;
|
||||
int status;
|
||||
char error[256];
|
||||
hdbValue v;
|
||||
|
||||
self = (pSctDrive)data;
|
||||
if(GetHdbProperty(self->node,"geterror", error, 256)){
|
||||
SCWrite(pCon,error, eError);
|
||||
return val;
|
||||
}
|
||||
return (float)self->node->value.v.doubleValue;
|
||||
}
|
||||
/*----------------------------------------------------------------
|
||||
returns NULL on failure, a new datastructure else
|
||||
------------------------------------------------------------------*/
|
||||
static pSctDrive SCTDRIVMakeObject(){
|
||||
pSctDrive self = NULL;
|
||||
|
||||
self = calloc(sizeof(SctDrive),1);
|
||||
if(self == NULL){
|
||||
return NULL;
|
||||
}
|
||||
self->pDes = CreateDescriptor("SctDriveAdapter");
|
||||
self->pDriv = CreateDrivableInterface();
|
||||
if(self->pDes == NULL || self->pDriv == NULL){
|
||||
free(self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->pDes->GetInterface = SCTDRIVGetInterface;
|
||||
self->pDriv->Halt = SCTDRIVHalt;
|
||||
self->pDriv->CheckLimits = SCTDRIVCheckLimits;
|
||||
self->pDriv->SetValue = SCTDRIVSetValue;
|
||||
self->pDriv->CheckStatus = SCTDRIVCheckStatus;
|
||||
self->pDriv->GetValue = SCTDRIVGetValue;
|
||||
|
||||
return self;
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int SctDriveCommand(SConnection *pCon, SicsInterp *sics, void *object,
|
||||
int argc, char *argv[]) {
|
||||
pSctDrive self = (pSctDrive)object;
|
||||
float val;
|
||||
|
||||
assert(self != NULL);
|
||||
|
||||
/*
|
||||
* only action: print value
|
||||
*/
|
||||
val = self->pDriv->GetValue(self,pCon);
|
||||
SCPrintf(pCon,eValue,"%s = %f", argv[0], val);
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
static void SctDriveKill(void *data){
|
||||
pSctDrive self = (pSctDrive)data;
|
||||
|
||||
if(self == NULL){
|
||||
return;
|
||||
}
|
||||
if(self->pDriv != NULL){
|
||||
free(self->pDriv);
|
||||
}
|
||||
if(self->pDes != NULL){
|
||||
DeleteDescriptor(self->pDes);
|
||||
}
|
||||
free(self);
|
||||
}
|
||||
/*---------------------------------------------------------------*/
|
||||
int SctMakeDriveAdapter(SConnection *pCon, SicsInterp *pSics, void *object,
|
||||
int argc, char *argv[]) {
|
||||
pSctDrive pNew = NULL;
|
||||
pSICSOBJ obj = NULL;
|
||||
|
||||
pNew = SCTDRIVMakeObject();
|
||||
if(pNew == NULL){
|
||||
SCWrite(pCon,"ERROR: out of memory in SctmakeDriveAdapter",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(argc < 4){
|
||||
SCWrite(pCon,"ERROR: not enough arguments for SctMakeDriveAdapter", eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pNew->node = FindHdbNode(NULL,argv[2], pCon);
|
||||
obj = FindCommandData(pSics,argv[3], "SctController");
|
||||
if(pNew->node == NULL || obj == NULL){
|
||||
SCWrite(pCon,"ERROR: node or controller not found", eError);
|
||||
SctDriveKill(pNew);
|
||||
return 0;
|
||||
}
|
||||
pNew->c =(SctController *)obj->pPrivate;
|
||||
AddCommand(pSics, argv[1], SctDriveCommand, SctDriveKill, pNew);
|
||||
SetHdbProperty(pNew->node,"sicsdev",argv[1]);
|
||||
return 1;
|
||||
}
|
Reference in New Issue
Block a user