First working version of the epics SICS adapter

This commit is contained in:
2014-10-27 12:14:56 +01:00
parent b2a63d59f0
commit dadb71245a
3 changed files with 188 additions and 6 deletions

View File

@ -5,13 +5,14 @@
* *
* copyright: see file COPYRIGHT * copyright: see file COPYRIGHT
* *
* Mark Koennecke, October-November 2014 * Mark Koennecke, October 2014
*/ */
#include <assert.h> #include <assert.h>
#include <sics.h> #include <sics.h>
#include <sicshipadaba.h> #include <sicshipadaba.h>
#include <cadef.h> #include <cadef.h>
#include <epicsMessageQueue.h> #include <epicsMessageQueue.h>
#include <epicsThread.h>
#include <messagepipe.h> #include <messagepipe.h>
/* /*
@ -38,10 +39,26 @@ typedef struct {
/*====================================================================================== /*======================================================================================
Code for reading PV's Code for reading PV's
======================================================================================*/ ======================================================================================*/
/*--------------------------------------------------------------------------------------*/
static int EpicsTask(void *userData) static int EpicsTask(void *userData)
{ {
WriteMessage mes;
/*
drive the main EPICS loop for subscriptions
*/
ca_poll(); ca_poll();
/*
process possible messages from the writing threads
*/
if(epicsMessageQueueTryReceive(writeQueue,&mes,sizeof(mes)) > 0){
if(mes.pCon == NULL){
traceIO("epics",mes.message);
} else {
SCWrite(mes.pCon,mes.message,eError);
SCDeleteConnection(mes.pCon);
}
}
return 1; return 1;
} }
/*---------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------*/
@ -90,6 +107,7 @@ static void epicsDataCallback(struct event_handler_args args)
{ {
pEpicsPriv priv = NULL; pEpicsPriv priv = NULL;
hdbValue v; hdbValue v;
char error[256];
priv = (pEpicsPriv)args.usr; priv = (pEpicsPriv)args.usr;
@ -116,8 +134,13 @@ static void epicsDataCallback(struct event_handler_args args)
copyHdbValue(&v,&priv->node->value); copyHdbValue(&v,&priv->node->value);
break; break;
} }
SetHdbProperty(priv->node,"geterror",NULL);
traceIO("epics","Received data for %s", priv->node->name); traceIO("epics","Received data for %s", priv->node->name);
NotifyHipadabaPar(priv->node,NULL); NotifyHipadabaPar(priv->node,NULL);
} else {
snprintf(error,sizeof(error),"ERROR: %s for node %s", ca_message(args.status), priv->node->name);
traceIO("epics",error);
SetHdbProperty(priv->node,"geterror",error);
} }
} }
/*--------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------*/
@ -146,7 +169,7 @@ static int epicsSubscribePV(void *message, void *userData)
} }
status = ca_create_subscription(subType,0,priv->pvchid, status = ca_create_subscription(subType,0,priv->pvchid,
DBE_VALUE,epicsDataCallback,priv,&eid); DBE_VALUE|DBE_ALARM,epicsDataCallback,priv,&eid);
if(status != ECA_NORMAL){ if(status != ECA_NORMAL){
SetHdbProperty(priv->node,"geterror", "Failed to subscribe to PV"); SetHdbProperty(priv->node,"geterror", "Failed to subscribe to PV");
return MPSTOP; return MPSTOP;
@ -187,6 +210,7 @@ static void connectPV(pHdb node, pEpicsPriv priv)
SConnection *con = NULL; SConnection *con = NULL;
char *geterror; char *geterror;
char error[256]; char error[256];
enum channel_state cs;
assert(priv != NULL); assert(priv != NULL);
@ -197,6 +221,11 @@ static void connectPV(pHdb node, pEpicsPriv priv)
if(priv->connected != 1){ if(priv->connected != 1){
connectPV(currentNode, priv); connectPV(currentNode, priv);
} }
cs = ca_state(priv->pvchid);
if(cs != cs_conn){
SCWrite(con,"ERROR: epics disconnected", eError);
return hdbAbort;
}
geterror = GetHdbProp(currentNode, "geterror"); geterror = GetHdbProp(currentNode, "geterror");
if (geterror != NULL) { if (geterror != NULL) {
snprintf(error,sizeof(error),"ERROR: %s", geterror); snprintf(error,sizeof(error),"ERROR: %s", geterror);
@ -244,11 +273,157 @@ static void connectPV(pHdb node, pEpicsPriv priv)
} }
/*============================================================================================== /*==============================================================================================
Writing Things. Writing can block, thus it has to run in its own thread. This raises the Writing Things. Writing can block, thus it has to run in its own thread. This raises the
question is how to propagate error messages. The solution is a EPICS message queue to which question how to propagate error messages. The solution is a EPICS message queue to which
writing threads post. The epics task will read this queue and do the actual printing in the writing threads post. The epics task will read this queue and do the actual printing in the
SICS main thread. A convention: NULL means to print to trace. SICS main thread. A convention: NULL means to print to trace.
================================================================================================*/ ================================================================================================*/
typedef struct {
SConnection *pCon;
hdbValue v;
char pvName[64];
} WritePar, *pWritePar;
/*----------------------------------------------------------------------------------------------*/
static void writeEpicsMessage(void *target, char *txt)
{
pWriteMessage wm = NULL;
wm = calloc(1,sizeof(WriteMessage));
if(wm != NULL){
if(target != NULL){
wm->pCon = SCCopyConnection(target);
}
strncpy(wm->message,txt,sizeof(wm->message));
epicsMessageQueueSend(writeQueue,wm,sizeof(WriteMessage));
}
}
/*----------------------------------------------------------------------------------------------*/
static void epicsEndCallback(struct event_handler_args args)
{
char message[512];
snprintf(message,sizeof(message),"%s finished with %s", (char *)args.usr,
ca_message(args.status));
writeEpicsMessage(NULL,message);
free(args.usr);
}
/*----------------------------------------------------------------------------------------------*/
static void EpicsWriteFunc(void *param)
{
pWritePar wp = (pWritePar)param;
pWriteMessage wm = NULL;
int status;
chid cid;
char error[512];
char *pv;
status = ca_context_create(ca_disable_preemptive_callback);
if(status != ECA_NORMAL){
writeEpicsMessage(wp->pCon,"ERROR: failed to create EPICS context for write");
goto cleanup;
}
status = ca_create_channel(wp->pvName,NULL,NULL,10,&cid);
if(status != ECA_NORMAL){
snprintf(error,sizeof(error),"ERROR: failed to create EPICS channel for %s", wp->pvName);
writeEpicsMessage(wp->pCon,error);
goto cleanup;
}
status = ca_pend_io(5.);
if(status != ECA_NORMAL){
snprintf(error,sizeof(error),"ERROR: failed to connect EPICS channel for %s", wp->pvName);
writeEpicsMessage(wp->pCon,error);
goto cleanup;
}
pv = strdup(wp->pvName);
switch(wp->v.dataType){
case HIPINT:
status = ca_put_callback(DBR_LONG,cid,&wp->v.v.intValue,epicsEndCallback,pv);
break;
case HIPFLOAT:
status = ca_put_callback(DBR_DOUBLE,cid,&wp->v.v.doubleValue,epicsEndCallback,pv);
break;
case HIPTEXT:
status = ca_put_callback(DBR_STRING,cid,wp->v.v.text,epicsEndCallback, pv);
break;
case HIPINTVARAR:
case HIPINTAR:
status = ca_array_put_callback(DBR_LONG,wp->v.arrayLength,
cid, wp->v.v.intArray,epicsEndCallback,pv);
break;
case HIPFLOATVARAR:
case HIPFLOATAR:
status = ca_array_put_callback(DBR_DOUBLE,wp->v.arrayLength,
cid, wp->v.v.floatArray,epicsEndCallback,pv);
break;
}
if(status != ECA_NORMAL){
snprintf(error,sizeof(error),"ERROR: failed to write to EPICS channel for %s with %d", wp->pvName, status);
writeEpicsMessage(wp->pCon,error);
goto cleanup;
}
writeEpicsMessage(wp->pCon,"OK");
ca_pend_io(0);
goto cleanup;
cleanup:
SCDeleteConnection(wp->pCon);
ReleaseHdbValue(&wp->v);
free(wp);
}
/*----------------------------------------------------------------------------------------------*/
static hdbCallbackReturn EPICSWriteCallback(pHdb currentNode,
void *userData,
pHdbMessage message)
{
hdbDataMessage *mm = NULL;
pWritePar par = NULL;
mm = GetHdbSetMessage(message);
if(mm != NULL){
par = calloc(1,sizeof(WritePar));
if(par == NULL){
SCWrite(mm->callData,"ERROR: out of memory in EPICSWriteCallback", eError);
return hdbAbort;
}
par->pCon = SCCopyConnection(mm->callData);
cloneHdbValue(mm->v,&par->v);
strncpy(par->pvName,(char *)userData,sizeof(par->pvName));
epicsThreadCreate("Write",
epicsThreadPriorityHigh,
epicsThreadStackMedium,
EpicsWriteFunc,
par);
}
return hdbContinue;
}
/*------------------------------------------------------------------------------------*/
static int EpicsConnectWrite(pSICSOBJ ccmd, SConnection * con,
Hdb * cmdNode, Hdb * par[], int nPar)
{
pHdb node = NULL;
pEpicsPriv priv = NULL;
if(nPar < 2){
SCWrite(con,"ERROR: need node and PV-name arguments to connectread", eError);
return 0;
}
node = FindHdbNode(NULL,par[0]->value.v.text,con);
if(node == NULL){
SCPrintf(con,eError,"ERROR: failed to locate node %s", par[0]->value.v.text);
return 0;
}
SetHdbProperty(node,"writepv", par[1]->value.v.text);
RemoveSetUpdateCallback(node);
AppendHipadabaCallback(node,MakeHipadabaCallback(EPICSWriteCallback,
strdup(par[1]->value.v.text),free));
SCSendOK(con);
return 1;
}
/*============================================================================================== /*==============================================================================================
SICS Hydraulics SICS Hydraulics
@ -262,12 +437,18 @@ int MakeEpicsAdapter(SConnection * con, SicsInterp * sics,
self = MakeSICSOBJv("epicsadapter", "EpicsAdapter", HIPNONE, usMugger); self = MakeSICSOBJv("epicsadapter", "EpicsAdapter", HIPNONE, usMugger);
createEPICSReadPipe(); createEPICSReadPipe();
writeQueue = epicsMessageQueueCreate(64,sizeof(WriteMessage));
child = AddSICSHdbPar(self->objectNode, child = AddSICSHdbPar(self->objectNode,
"connectread", usMugger, MakeSICSFunc(EpicsConnectRead)); "connectread", usMugger, MakeSICSFunc(EpicsConnectRead));
AddSICSHdbPar(child, "node", usMugger, MakeHdbText("")); AddSICSHdbPar(child, "node", usMugger, MakeHdbText(""));
AddSICSHdbPar(child, "pvname", usMugger, MakeHdbText("")); AddSICSHdbPar(child, "pvname", usMugger, MakeHdbText(""));
child = AddSICSHdbPar(self->objectNode,
"connectwrite", usMugger, MakeSICSFunc(EpicsConnectWrite));
AddSICSHdbPar(child, "node", usMugger, MakeHdbText(""));
AddSICSHdbPar(child, "pvname", usMugger, MakeHdbText(""));
AddCommand(pServ->pSics, "epicsadapter", InterInvokeSICSOBJ, KillSICSOBJ, self); AddCommand(pServ->pSics, "epicsadapter", InterInvokeSICSOBJ, KillSICSOBJ, self);
return 1; return 1;
} }

View File

@ -25,7 +25,8 @@ OBJ=psi.o buffer.o ruli.o sps.o pimotor.o charbychar.o\
rebin.o sanslirebin.o lmd200.o slsvme.o julprot.o sinqhttpprot.o \ rebin.o sanslirebin.o lmd200.o slsvme.o julprot.o sinqhttpprot.o \
pmacprot.o pfeifferprot.o termprot.o phytron.o autowin.o eigera2.o \ pmacprot.o pfeifferprot.o termprot.o phytron.o autowin.o eigera2.o \
tclClock.o tclDate.o tclUnixTime.o jvlprot.o \ tclClock.o tclDate.o tclUnixTime.o jvlprot.o \
eigermono.o sputterprot.o zwickroll.o astriumnet.o poldifold.o eigermono.o sputterprot.o zwickroll.o astriumnet.o poldifold.o \
epicsadapter.o
.SECONDARY.: sanslirebin.c .SECONDARY.: sanslirebin.c

View File

@ -13,7 +13,7 @@ include $(SICSROOT)/sics/sllinux_def
CC = gcc CC = gcc
CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 $(NI) -I$(TCLINC) -Ihardsup \ CFLAGS = -I$(HDFROOT)/include -I$(HDFROOT)/include/os/Linux -DHDF4 -DHDF5 $(NI) -I$(TCLINC) -Ihardsup \
-I$(SICSROOT)/sics -I.. -I. -MMD -DCYGNUS -DNONINTF $(DBG) \ -I$(SICSROOT)/sics -I.. -I. -MMD -DCYGNUS -DNONINTF $(DBG) \
$(DFORTIFY) -Wall -Wno-unused -Wunused-value -Wno-comment \ $(DFORTIFY) -Wall -Wno-unused -Wunused-value -Wno-comment \
-Wno-switch -Werror -Wno-switch -Werror