- More debugging of scriptcontext, mostly working now

- Created driveable SICSobj for standalone and as an adapter
This commit is contained in:
koennecke
2008-07-14 07:22:41 +00:00
parent 8f50089f7c
commit 0fd55c2c39
10 changed files with 433 additions and 35 deletions

17
ascon.c
View File

@ -117,7 +117,13 @@ 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) {
switch(errno) {
case EINPROGRESS:
case EALREADY:
case EISCONN:
a->state = AsconConnecting;
break;
default:
AsconError(a, "connect failed:", errno);
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;
}
}

View File

@ -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;
}
@ -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;

View File

@ -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);
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)
{

View File

@ -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)

View File

@ -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)

View File

@ -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);
}

337
sctdriveobj.c Normal file
View File

@ -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 <sics.h>
#include <tcl.h>
#include <sicsobj.h>
#include <scriptcontext.h>
#include <sicshipadaba.h>
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;
}

View File

@ -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]);
}

View File

@ -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

View File

@ -6,7 +6,7 @@
#DFORTIFY= -DFORTIFY
#FORTIFYOBJ= fortify.o strdup.o
#DFORTIFY= -p
DFORTIFY= -pg
MFLAGS=-f makefile_linux$(DUMMY)