Fixed indentation in epicsadapater.c
Corrected a header file include in zebraswap.c
This commit is contained in:
742
epicsadapter.c
742
epicsadapter.c
@ -1,12 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* This is a general purpose adapter between SICS and EPICS. It provides callbacks
|
* This is a general purpose adapter between SICS and EPICS. It provides callbacks
|
||||||
* which allows Hipadaba nodes to be connected to EPICS PV's for both reading and
|
* which allows Hipadaba nodes to be connected to EPICS PV's for both reading and
|
||||||
* writing.
|
* writing.
|
||||||
*
|
*
|
||||||
* copyright: see file COPYRIGHT
|
* copyright: see file COPYRIGHT
|
||||||
*
|
*
|
||||||
* Mark Koennecke, October - November 2014
|
* Mark Koennecke, October - November 2014
|
||||||
*/
|
*/
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sics.h>
|
#include <sics.h>
|
||||||
#include <sicshipadaba.h>
|
#include <sicshipadaba.h>
|
||||||
@ -16,31 +16,31 @@
|
|||||||
#include <messagepipe.h>
|
#include <messagepipe.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
One of those: alarmString.h cannot be doubly included into the
|
One of those: alarmString.h cannot be doubly included into the
|
||||||
same application
|
same application
|
||||||
*/
|
*/
|
||||||
#include <alarmString.h>
|
#include <alarmString.h>
|
||||||
/* extern char *epicsAlarmConditionStrings[]; */
|
/* extern char *epicsAlarmConditionStrings[]; */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we have a SICS tasks which polls EPICS regularly.
|
* we have a SICS tasks which polls EPICS regularly.
|
||||||
*/
|
*/
|
||||||
static long epicsTaskID = -1L;
|
static long epicsTaskID = -1L;
|
||||||
static pMP readPipe = NULL;
|
static pMP readPipe = NULL;
|
||||||
static epicsMessageQueueId writeQueue;
|
static epicsMessageQueueId writeQueue;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char pvname[64];
|
char pvname[64];
|
||||||
int connected;
|
int connected;
|
||||||
pHdb node;
|
pHdb node;
|
||||||
chid pvchid;
|
chid pvchid;
|
||||||
chtype pvtype;
|
chtype pvtype;
|
||||||
}EpicsPriv, *pEpicsPriv;
|
}EpicsPriv, *pEpicsPriv;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SConnection *pCon;
|
SConnection *pCon;
|
||||||
char message[512];
|
char message[512];
|
||||||
} WriteMessage, *pWriteMessage;
|
} WriteMessage, *pWriteMessage;
|
||||||
|
|
||||||
/*======================================================================================
|
/*======================================================================================
|
||||||
@ -48,448 +48,448 @@ typedef struct {
|
|||||||
======================================================================================*/
|
======================================================================================*/
|
||||||
static int EpicsTask(void *userData)
|
static int EpicsTask(void *userData)
|
||||||
{
|
{
|
||||||
pWriteMessage mes;
|
pWriteMessage mes;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
drive the main EPICS loop for subscriptions
|
drive the main EPICS loop for subscriptions
|
||||||
*/
|
*/
|
||||||
ca_poll();
|
ca_poll();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
process possible messages from the writing threads
|
process possible messages from the writing threads
|
||||||
*/
|
*/
|
||||||
if(epicsMessageQueueTryReceive(writeQueue,&mes,sizeof(mes)) > 0){
|
if(epicsMessageQueueTryReceive(writeQueue,&mes,sizeof(mes)) > 0){
|
||||||
if(mes->pCon == NULL){
|
if(mes->pCon == NULL){
|
||||||
traceIO("epics",mes->message);
|
traceIO("epics",mes->message);
|
||||||
} else {
|
} else {
|
||||||
SCWrite(mes->pCon,mes->message,eError);
|
SCWrite(mes->pCon,mes->message,eError);
|
||||||
SCDeleteConnection(mes->pCon);
|
SCDeleteConnection(mes->pCon);
|
||||||
}
|
}
|
||||||
free(mes);
|
free(mes);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------------*/
|
||||||
static int makeEPICSContext(void *message, void *userData)
|
static int makeEPICSContext(void *message, void *userData)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
pEpicsPriv priv = NULL;
|
pEpicsPriv priv = NULL;
|
||||||
|
|
||||||
if(epicsTaskID < 0){
|
if(epicsTaskID < 0){
|
||||||
status = ca_context_create(ca_disable_preemptive_callback);
|
status = ca_context_create(ca_disable_preemptive_callback);
|
||||||
if(status != ECA_NORMAL){
|
if(status != ECA_NORMAL){
|
||||||
priv = (pEpicsPriv)message;
|
priv = (pEpicsPriv)message;
|
||||||
SetHdbProperty(priv->node,"geterror", "Failed to create EPICS context");
|
SetHdbProperty(priv->node,"geterror", "Failed to create EPICS context");
|
||||||
return MPSTOP;
|
return MPSTOP;
|
||||||
}
|
}
|
||||||
epicsTaskID = TaskRegisterN(pServ->pTasker,
|
epicsTaskID = TaskRegisterN(pServ->pTasker,
|
||||||
"epics",
|
"epics",
|
||||||
EpicsTask,
|
EpicsTask,
|
||||||
NULL,NULL,NULL,1
|
NULL,NULL,NULL,1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return MPCONTINUE;
|
return MPCONTINUE;
|
||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------------------*/
|
||||||
static int epicsConnectPV(void *message, void *userData)
|
static int epicsConnectPV(void *message, void *userData)
|
||||||
{
|
{
|
||||||
pEpicsPriv priv = NULL;
|
pEpicsPriv priv = NULL;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
priv = (pEpicsPriv)message;
|
priv = (pEpicsPriv)message;
|
||||||
|
|
||||||
status = ca_create_channel(priv->pvname,NULL,NULL,10,&priv->pvchid);
|
status = ca_create_channel(priv->pvname,NULL,NULL,10,&priv->pvchid);
|
||||||
if(status != ECA_NORMAL){
|
if(status != ECA_NORMAL){
|
||||||
SetHdbProperty(priv->node,"geterror", "Failed to connect to PV");
|
SetHdbProperty(priv->node,"geterror", "Failed to connect to PV");
|
||||||
return MPSTOP;
|
return MPSTOP;
|
||||||
}
|
}
|
||||||
status = ca_pend_io(0.2);
|
status = ca_pend_io(0.2);
|
||||||
if(status != ECA_NORMAL){
|
if(status != ECA_NORMAL){
|
||||||
SetHdbProperty(priv->node,"geterror", "Timeout connecting to PV");
|
SetHdbProperty(priv->node,"geterror", "Timeout connecting to PV");
|
||||||
return MPSTOP;
|
return MPSTOP;
|
||||||
}
|
}
|
||||||
return MPCONTINUE;
|
return MPCONTINUE;
|
||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------------------*/
|
||||||
static void epicsDataCallback(struct event_handler_args args)
|
static void epicsDataCallback(struct event_handler_args args)
|
||||||
{
|
{
|
||||||
pEpicsPriv priv = NULL;
|
pEpicsPriv priv = NULL;
|
||||||
hdbValue v;
|
hdbValue v;
|
||||||
char error[256];
|
char error[256];
|
||||||
|
|
||||||
priv = (pEpicsPriv)args.usr;
|
priv = (pEpicsPriv)args.usr;
|
||||||
|
|
||||||
if(args.status == ECA_NORMAL){
|
if(args.status == ECA_NORMAL){
|
||||||
switch(priv->node->value.dataType){
|
switch(priv->node->value.dataType){
|
||||||
case HIPTEXT:
|
case HIPTEXT:
|
||||||
free(priv->node->value.v.text);
|
free(priv->node->value.v.text);
|
||||||
priv->node->value.v.text = strdup((char *)args.dbr);
|
priv->node->value.v.text = strdup((char *)args.dbr);
|
||||||
break;
|
break;
|
||||||
case HIPINT:
|
case HIPINT:
|
||||||
priv->node->value.v.intValue = *(int *)args.dbr;
|
priv->node->value.v.intValue = *(int *)args.dbr;
|
||||||
break;
|
break;
|
||||||
case HIPFLOAT:
|
case HIPFLOAT:
|
||||||
priv->node->value.v.doubleValue = *(double *)args.dbr;
|
priv->node->value.v.doubleValue = *(double *)args.dbr;
|
||||||
break;
|
break;
|
||||||
case HIPINTAR:
|
case HIPINTAR:
|
||||||
case HIPINTVARAR:
|
case HIPINTVARAR:
|
||||||
v = MakeHdbIntArray(args.count,(int *)args.dbr);
|
v = MakeHdbIntArray(args.count,(int *)args.dbr);
|
||||||
copyHdbValue(&v,&priv->node->value);
|
copyHdbValue(&v,&priv->node->value);
|
||||||
break;
|
break;
|
||||||
case HIPFLOATAR:
|
case HIPFLOATAR:
|
||||||
case HIPFLOATVARAR:
|
case HIPFLOATVARAR:
|
||||||
v = MakeHdbFloatArray(args.count,(double *)args.dbr);
|
v = MakeHdbFloatArray(args.count,(double *)args.dbr);
|
||||||
copyHdbValue(&v,&priv->node->value);
|
copyHdbValue(&v,&priv->node->value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SetHdbProperty(priv->node,"geterror",NULL);
|
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 {
|
} else {
|
||||||
snprintf(error,sizeof(error),"ERROR: %s for node %s", ca_message(args.status), priv->node->name);
|
snprintf(error,sizeof(error),"ERROR: %s for node %s", ca_message(args.status), priv->node->name);
|
||||||
traceIO("epics",error);
|
traceIO("epics",error);
|
||||||
SetHdbProperty(priv->node,"geterror",error);
|
SetHdbProperty(priv->node,"geterror",error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------------------*/
|
||||||
static int epicsSubscribePV(void *message, void *userData)
|
static int epicsSubscribePV(void *message, void *userData)
|
||||||
{
|
{
|
||||||
pEpicsPriv priv = NULL;
|
pEpicsPriv priv = NULL;
|
||||||
int status;
|
int status;
|
||||||
chtype subType = DBR_STRING;
|
chtype subType = DBR_STRING;
|
||||||
evid eid;
|
evid eid;
|
||||||
|
|
||||||
priv = (pEpicsPriv)message;
|
priv = (pEpicsPriv)message;
|
||||||
switch(priv->node->value.dataType){
|
switch(priv->node->value.dataType){
|
||||||
case HIPTEXT:
|
case HIPTEXT:
|
||||||
subType = DBR_STRING;
|
subType = DBR_STRING;
|
||||||
break;
|
break;
|
||||||
case HIPINT:
|
case HIPINT:
|
||||||
case HIPINTAR:
|
case HIPINTAR:
|
||||||
case HIPINTVARAR:
|
case HIPINTVARAR:
|
||||||
subType = DBR_LONG;
|
subType = DBR_LONG;
|
||||||
break;
|
break;
|
||||||
case HIPFLOAT:
|
case HIPFLOAT:
|
||||||
case HIPFLOATAR:
|
case HIPFLOATAR:
|
||||||
case HIPFLOATVARAR:
|
case HIPFLOATVARAR:
|
||||||
subType = DBR_DOUBLE;
|
subType = DBR_DOUBLE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = ca_create_subscription(subType,0,priv->pvchid,
|
status = ca_create_subscription(subType,0,priv->pvchid,
|
||||||
DBE_VALUE|DBE_ALARM,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return MPCONTINUE;
|
return MPCONTINUE;
|
||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------------------*/
|
||||||
static void createEPICSReadPipe()
|
static void createEPICSReadPipe()
|
||||||
{
|
{
|
||||||
readPipe = MakeMP();
|
readPipe = MakeMP();
|
||||||
AppendMPFilter(readPipe,makeEPICSContext,NULL,NULL);
|
AppendMPFilter(readPipe,makeEPICSContext,NULL,NULL);
|
||||||
AppendMPFilter(readPipe,epicsConnectPV,NULL,NULL);
|
AppendMPFilter(readPipe,epicsConnectPV,NULL,NULL);
|
||||||
AppendMPFilter(readPipe,epicsSubscribePV,NULL,NULL);
|
AppendMPFilter(readPipe,epicsSubscribePV,NULL,NULL);
|
||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------------------*/
|
||||||
static void connectPV(pHdb node, pEpicsPriv priv)
|
static void connectPV(pHdb node, pEpicsPriv priv)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
SetHdbProperty(node,"geterror", NULL);
|
SetHdbProperty(node,"geterror", NULL);
|
||||||
priv->node = node;
|
priv->node = node;
|
||||||
status = MPprocess(readPipe, priv);
|
status = MPprocess(readPipe, priv);
|
||||||
if(status == MPCONTINUE){
|
if(status == MPCONTINUE){
|
||||||
priv->connected = 1;
|
priv->connected = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------------------
|
||||||
This is the Hipadaba callback function
|
This is the Hipadaba callback function
|
||||||
--------------------------------------------------------------------------------------*/
|
--------------------------------------------------------------------------------------*/
|
||||||
static hdbCallbackReturn EPICSReadCallback(pHdb currentNode,
|
static hdbCallbackReturn EPICSReadCallback(pHdb currentNode,
|
||||||
void *userData,
|
void *userData,
|
||||||
pHdbMessage message)
|
pHdbMessage message)
|
||||||
{
|
{
|
||||||
pEpicsPriv priv = (pEpicsPriv)userData;
|
pEpicsPriv priv = (pEpicsPriv)userData;
|
||||||
hdbDataMessage *mm = NULL;
|
hdbDataMessage *mm = NULL;
|
||||||
SConnection *con = NULL;
|
SConnection *con = NULL;
|
||||||
char *geterror;
|
char *geterror;
|
||||||
char error[256];
|
char error[256];
|
||||||
enum channel_state cs;
|
enum channel_state cs;
|
||||||
|
|
||||||
assert(priv != NULL);
|
assert(priv != NULL);
|
||||||
|
|
||||||
mm = GetHdbGetMessage(message);
|
mm = GetHdbGetMessage(message);
|
||||||
if (mm != NULL) {
|
if (mm != NULL) {
|
||||||
con = mm->callData;
|
con = mm->callData;
|
||||||
|
|
||||||
if(priv->connected != 1){
|
if(priv->connected != 1){
|
||||||
connectPV(currentNode, priv);
|
connectPV(currentNode, priv);
|
||||||
}
|
}
|
||||||
cs = ca_state(priv->pvchid);
|
cs = ca_state(priv->pvchid);
|
||||||
if(cs != cs_conn){
|
if(cs != cs_conn){
|
||||||
SCWrite(con,"ERROR: epics disconnected", eError);
|
SCWrite(con,"ERROR: epics disconnected", eError);
|
||||||
return hdbAbort;
|
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);
|
||||||
SCWrite(con, error, eError);
|
SCWrite(con, error, eError);
|
||||||
if (mm->v->dataType == HIPTEXT) {
|
if (mm->v->dataType == HIPTEXT) {
|
||||||
if (mm->v->v.text != NULL) {
|
if (mm->v->v.text != NULL) {
|
||||||
free(mm->v->v.text);
|
free(mm->v->v.text);
|
||||||
}
|
|
||||||
mm->v->v.text = strdup(error);
|
|
||||||
}
|
|
||||||
return hdbAbort;
|
|
||||||
}
|
|
||||||
return hdbContinue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hdbContinue;
|
|
||||||
}
|
|
||||||
/*------------------------------------------------------------------------------------*/
|
|
||||||
static int EpicsConnectRead(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
priv = calloc(1,sizeof(EpicsPriv));
|
|
||||||
priv->node = node;
|
|
||||||
strncpy(priv->pvname,par[1]->value.v.text,sizeof(priv->pvname));
|
|
||||||
SetHdbProperty(node,"readpv", par[1]->value.v.text);
|
|
||||||
AppendHipadabaCallback(node,MakeHipadabaCallback(EPICSReadCallback, priv,free));
|
|
||||||
connectPV(node,priv);
|
|
||||||
|
|
||||||
SCSendOK(con);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
/*==============================================================================================
|
mm->v->v.text = strdup(error);
|
||||||
Writing Things. Writing can block, thus it has to run in its own thread. This raises the
|
}
|
||||||
question how to propagate error messages. The solution is a EPICS message queue to which
|
return hdbAbort;
|
||||||
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.
|
return hdbContinue;
|
||||||
|
}
|
||||||
|
|
||||||
================================================================================================*/
|
return hdbContinue;
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------------------------------------*/
|
||||||
|
static int EpicsConnectRead(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv = calloc(1,sizeof(EpicsPriv));
|
||||||
|
priv->node = node;
|
||||||
|
strncpy(priv->pvname,par[1]->value.v.text,sizeof(priv->pvname));
|
||||||
|
SetHdbProperty(node,"readpv", par[1]->value.v.text);
|
||||||
|
AppendHipadabaCallback(node,MakeHipadabaCallback(EPICSReadCallback, priv,free));
|
||||||
|
connectPV(node,priv);
|
||||||
|
|
||||||
|
SCSendOK(con);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*==============================================================================================
|
||||||
|
Writing Things. Writing can block, thus it has to run in its own thread. This raises the
|
||||||
|
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
|
||||||
|
SICS main thread. A convention: NULL means to print to trace.
|
||||||
|
|
||||||
|
================================================================================================*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SConnection *pCon;
|
SConnection *pCon;
|
||||||
hdbValue v;
|
hdbValue v;
|
||||||
char pvName[64];
|
char pvName[64];
|
||||||
} WritePar, *pWritePar;
|
} WritePar, *pWritePar;
|
||||||
/*----------------------------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------------------------*/
|
||||||
static void writeEpicsMessage(void *target, char *txt)
|
static void writeEpicsMessage(void *target, char *txt)
|
||||||
{
|
{
|
||||||
pWriteMessage wm = NULL;
|
pWriteMessage wm = NULL;
|
||||||
|
|
||||||
wm = calloc(1,sizeof(WriteMessage));
|
wm = calloc(1,sizeof(WriteMessage));
|
||||||
if(wm != NULL){
|
if(wm != NULL){
|
||||||
if(target != NULL){
|
if(target != NULL){
|
||||||
wm->pCon = SCCopyConnection(target);
|
wm->pCon = SCCopyConnection(target);
|
||||||
}
|
}
|
||||||
strncpy(wm->message,txt,sizeof(wm->message));
|
strncpy(wm->message,txt,sizeof(wm->message));
|
||||||
epicsMessageQueueSend(writeQueue,&wm,sizeof(pWriteMessage));
|
epicsMessageQueueSend(writeQueue,&wm,sizeof(pWriteMessage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*----------------------------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------------------------
|
||||||
To my surprise this is never called. May be, when the thread terminates anyway,
|
To my surprise this is never called. May be, when the thread terminates anyway,
|
||||||
epics does not know anymore that the callback existed or how to call it.
|
epics does not know anymore that the callback existed or how to call it.
|
||||||
------------------------------------------------------------------------------------------------*/
|
------------------------------------------------------------------------------------------------*/
|
||||||
static void epicsEndCallback(struct event_handler_args args)
|
static void epicsEndCallback(struct event_handler_args args)
|
||||||
{
|
{
|
||||||
char message[512];
|
char message[512];
|
||||||
snprintf(message,sizeof(message),"%s finished with %s", (char *)args.usr,
|
snprintf(message,sizeof(message),"%s finished with %s", (char *)args.usr,
|
||||||
ca_message(args.status));
|
ca_message(args.status));
|
||||||
writeEpicsMessage(NULL,message);
|
writeEpicsMessage(NULL,message);
|
||||||
free(args.usr);
|
free(args.usr);
|
||||||
}
|
}
|
||||||
/*----------------------------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------------------------*/
|
||||||
static void EpicsWriteFunc(void *param)
|
static void EpicsWriteFunc(void *param)
|
||||||
{
|
{
|
||||||
pWritePar wp = (pWritePar)param;
|
pWritePar wp = (pWritePar)param;
|
||||||
pWriteMessage wm = NULL;
|
pWriteMessage wm = NULL;
|
||||||
int status;
|
int status;
|
||||||
chid cid;
|
chid cid;
|
||||||
char error[512];
|
char error[512];
|
||||||
char *pv;
|
char *pv;
|
||||||
|
|
||||||
status = ca_context_create(ca_disable_preemptive_callback);
|
status = ca_context_create(ca_disable_preemptive_callback);
|
||||||
if(status != ECA_NORMAL){
|
if(status != ECA_NORMAL){
|
||||||
writeEpicsMessage(wp->pCon,"ERROR: failed to create EPICS context for write");
|
writeEpicsMessage(wp->pCon,"ERROR: failed to create EPICS context for write");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
status = ca_create_channel(wp->pvName,NULL,NULL,10,&cid);
|
status = ca_create_channel(wp->pvName,NULL,NULL,10,&cid);
|
||||||
if(status != ECA_NORMAL){
|
if(status != ECA_NORMAL){
|
||||||
snprintf(error,sizeof(error),"ERROR: failed to create EPICS channel for %s", wp->pvName);
|
snprintf(error,sizeof(error),"ERROR: failed to create EPICS channel for %s", wp->pvName);
|
||||||
writeEpicsMessage(wp->pCon,error);
|
writeEpicsMessage(wp->pCon,error);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
status = ca_pend_io(0.5);
|
status = ca_pend_io(0.5);
|
||||||
if(status != ECA_NORMAL){
|
if(status != ECA_NORMAL){
|
||||||
snprintf(error,sizeof(error),"ERROR: failed to connect EPICS channel for %s", wp->pvName);
|
snprintf(error,sizeof(error),"ERROR: failed to connect EPICS channel for %s", wp->pvName);
|
||||||
writeEpicsMessage(wp->pCon,error);
|
writeEpicsMessage(wp->pCon,error);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
pv = strdup(wp->pvName);
|
pv = strdup(wp->pvName);
|
||||||
switch(wp->v.dataType){
|
switch(wp->v.dataType){
|
||||||
case HIPINT:
|
case HIPINT:
|
||||||
status = ca_put_callback(DBR_LONG,cid,&wp->v.v.intValue,epicsEndCallback,pv);
|
status = ca_put_callback(DBR_LONG,cid,&wp->v.v.intValue,epicsEndCallback,pv);
|
||||||
break;
|
break;
|
||||||
case HIPFLOAT:
|
case HIPFLOAT:
|
||||||
status = ca_put_callback(DBR_DOUBLE,cid,&wp->v.v.doubleValue,epicsEndCallback,pv);
|
status = ca_put_callback(DBR_DOUBLE,cid,&wp->v.v.doubleValue,epicsEndCallback,pv);
|
||||||
break;
|
break;
|
||||||
case HIPTEXT:
|
case HIPTEXT:
|
||||||
status = ca_put_callback(DBR_STRING,cid,wp->v.v.text,epicsEndCallback, pv);
|
status = ca_put_callback(DBR_STRING,cid,wp->v.v.text,epicsEndCallback, pv);
|
||||||
break;
|
break;
|
||||||
case HIPINTVARAR:
|
case HIPINTVARAR:
|
||||||
case HIPINTAR:
|
case HIPINTAR:
|
||||||
status = ca_array_put_callback(DBR_LONG,wp->v.arrayLength,
|
status = ca_array_put_callback(DBR_LONG,wp->v.arrayLength,
|
||||||
cid, wp->v.v.intArray,epicsEndCallback,pv);
|
cid, wp->v.v.intArray,epicsEndCallback,pv);
|
||||||
break;
|
break;
|
||||||
case HIPFLOATVARAR:
|
case HIPFLOATVARAR:
|
||||||
case HIPFLOATAR:
|
case HIPFLOATAR:
|
||||||
status = ca_array_put_callback(DBR_DOUBLE,wp->v.arrayLength,
|
status = ca_array_put_callback(DBR_DOUBLE,wp->v.arrayLength,
|
||||||
cid, wp->v.v.floatArray,epicsEndCallback,pv);
|
cid, wp->v.v.floatArray,epicsEndCallback,pv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(status != ECA_NORMAL){
|
if(status != ECA_NORMAL){
|
||||||
snprintf(error,sizeof(error),"ERROR: failed to write to EPICS channel for %s with %d", wp->pvName, status);
|
snprintf(error,sizeof(error),"ERROR: failed to write to EPICS channel for %s with %d", wp->pvName, status);
|
||||||
writeEpicsMessage(wp->pCon,error);
|
writeEpicsMessage(wp->pCon,error);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
writeEpicsMessage(wp->pCon,"OK");
|
writeEpicsMessage(wp->pCon,"OK");
|
||||||
snprintf(error,sizeof(error),"Writing data for PV %s", wp->pvName);
|
snprintf(error,sizeof(error),"Writing data for PV %s", wp->pvName);
|
||||||
writeEpicsMessage(NULL,error);
|
writeEpicsMessage(NULL,error);
|
||||||
|
|
||||||
ca_pend_io(0);
|
ca_pend_io(0);
|
||||||
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
cleanup:
|
cleanup:
|
||||||
SCDeleteConnection(wp->pCon);
|
SCDeleteConnection(wp->pCon);
|
||||||
ReleaseHdbValue(&wp->v);
|
ReleaseHdbValue(&wp->v);
|
||||||
free(wp);
|
free(wp);
|
||||||
free(pv);
|
free(pv);
|
||||||
ca_clear_channel(cid);
|
ca_clear_channel(cid);
|
||||||
ca_context_destroy();
|
/* ca_context_destroy(); */
|
||||||
}
|
}
|
||||||
/*----------------------------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------------------------*/
|
||||||
static hdbCallbackReturn EPICSWriteCallback(pHdb currentNode,
|
static hdbCallbackReturn EPICSWriteCallback(pHdb currentNode,
|
||||||
void *userData,
|
void *userData,
|
||||||
pHdbMessage message)
|
pHdbMessage message)
|
||||||
{
|
{
|
||||||
hdbDataMessage *mm = NULL;
|
hdbDataMessage *mm = NULL;
|
||||||
pWritePar par = NULL;
|
pWritePar par = NULL;
|
||||||
|
|
||||||
mm = GetHdbSetMessage(message);
|
mm = GetHdbSetMessage(message);
|
||||||
if(mm != NULL){
|
if(mm != NULL){
|
||||||
par = calloc(1,sizeof(WritePar));
|
par = calloc(1,sizeof(WritePar));
|
||||||
if(par == NULL){
|
if(par == NULL){
|
||||||
SCWrite(mm->callData,"ERROR: out of memory in EPICSWriteCallback", eError);
|
SCWrite(mm->callData,"ERROR: out of memory in EPICSWriteCallback", eError);
|
||||||
return hdbAbort;
|
return hdbAbort;
|
||||||
}
|
}
|
||||||
if(mm->callData != NULL){
|
if(mm->callData != NULL){
|
||||||
par->pCon = SCCopyConnection(mm->callData);
|
par->pCon = SCCopyConnection(mm->callData);
|
||||||
}
|
}
|
||||||
cloneHdbValue(mm->v,&par->v);
|
cloneHdbValue(mm->v,&par->v);
|
||||||
strncpy(par->pvName,(char *)userData,sizeof(par->pvName));
|
strncpy(par->pvName,(char *)userData,sizeof(par->pvName));
|
||||||
epicsThreadCreate("Write",
|
epicsThreadCreate("Write",
|
||||||
epicsThreadPriorityHigh,
|
epicsThreadPriorityHigh,
|
||||||
epicsThreadStackSmall,
|
epicsThreadStackMedium,
|
||||||
EpicsWriteFunc,
|
EpicsWriteFunc,
|
||||||
par);
|
par);
|
||||||
}
|
}
|
||||||
|
|
||||||
return hdbContinue;
|
return hdbContinue;
|
||||||
}
|
}
|
||||||
/*------------------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------------------*/
|
||||||
static int EpicsConnectWrite(pSICSOBJ ccmd, SConnection * con,
|
static int EpicsConnectWrite(pSICSOBJ ccmd, SConnection * con,
|
||||||
Hdb * cmdNode, Hdb * par[], int nPar)
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||||
{
|
{
|
||||||
pHdb node = NULL;
|
pHdb node = NULL;
|
||||||
pEpicsPriv priv = NULL;
|
pEpicsPriv priv = NULL;
|
||||||
|
|
||||||
if(nPar < 2){
|
if(nPar < 2){
|
||||||
SCWrite(con,"ERROR: need node and PV-name arguments to connectread", eError);
|
SCWrite(con,"ERROR: need node and PV-name arguments to connectread", eError);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = FindHdbNode(NULL,par[0]->value.v.text,con);
|
node = FindHdbNode(NULL,par[0]->value.v.text,con);
|
||||||
if(node == NULL){
|
if(node == NULL){
|
||||||
SCPrintf(con,eError,"ERROR: failed to locate node %s", par[0]->value.v.text);
|
SCPrintf(con,eError,"ERROR: failed to locate node %s", par[0]->value.v.text);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetHdbProperty(node,"writepv", par[1]->value.v.text);
|
SetHdbProperty(node,"writepv", par[1]->value.v.text);
|
||||||
RemoveSetUpdateCallback(node);
|
RemoveSetUpdateCallback(node);
|
||||||
AppendHipadabaCallback(node,MakeHipadabaCallback(EPICSWriteCallback,
|
AppendHipadabaCallback(node,MakeHipadabaCallback(EPICSWriteCallback,
|
||||||
strdup(par[1]->value.v.text),free));
|
strdup(par[1]->value.v.text),free));
|
||||||
|
|
||||||
SCSendOK(con);
|
SCSendOK(con);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*==============================================================================================
|
/*==============================================================================================
|
||||||
SICS Hydraulics
|
SICS Hydraulics
|
||||||
================================================================================================*/
|
================================================================================================*/
|
||||||
static int EpicsConvertAlarm(pSICSOBJ ccmd, SConnection * con,
|
static int EpicsConvertAlarm(pSICSOBJ ccmd, SConnection * con,
|
||||||
Hdb * cmdNode, Hdb * par[], int nPar)
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||||
{
|
{
|
||||||
pHdb node = NULL;
|
pHdb node = NULL;
|
||||||
char value[256];
|
char value[256];
|
||||||
|
|
||||||
if(nPar < 1){
|
if(nPar < 1){
|
||||||
SCWrite(con,"ERROR: need alarm code to convert", eError);
|
SCWrite(con,"ERROR: need alarm code to convert", eError);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(value,sizeof(value),"%s", epicsAlarmConditionStrings[par[0]->value.v.intValue]);
|
snprintf(value,sizeof(value),"%s", epicsAlarmConditionStrings[par[0]->value.v.intValue]);
|
||||||
SCWrite(con,value,eValue);
|
SCWrite(con,value,eValue);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------------------------*/
|
||||||
int MakeEpicsAdapter(SConnection * con, SicsInterp * sics,
|
int MakeEpicsAdapter(SConnection * con, SicsInterp * sics,
|
||||||
void *object, int argc, char *argv[])
|
void *object, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
pSICSOBJ self = NULL;
|
pSICSOBJ self = NULL;
|
||||||
pHdb child, par;
|
pHdb child, par;
|
||||||
|
|
||||||
self = MakeSICSOBJv("epicsadapter", "EpicsAdapter", HIPNONE, usMugger);
|
self = MakeSICSOBJv("epicsadapter", "EpicsAdapter", HIPNONE, usMugger);
|
||||||
createEPICSReadPipe();
|
createEPICSReadPipe();
|
||||||
writeQueue = epicsMessageQueueCreate(64,sizeof(pWriteMessage));
|
writeQueue = epicsMessageQueueCreate(64,sizeof(pWriteMessage));
|
||||||
|
|
||||||
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,
|
child = AddSICSHdbPar(self->objectNode,
|
||||||
"connectwrite", usMugger, MakeSICSFunc(EpicsConnectWrite));
|
"connectwrite", usMugger, MakeSICSFunc(EpicsConnectWrite));
|
||||||
AddSICSHdbPar(child, "node", usMugger, MakeHdbText(""));
|
AddSICSHdbPar(child, "node", usMugger, MakeHdbText(""));
|
||||||
AddSICSHdbPar(child, "pvname", usMugger, MakeHdbText(""));
|
AddSICSHdbPar(child, "pvname", usMugger, MakeHdbText(""));
|
||||||
|
|
||||||
child = AddSICSHdbPar(self->objectNode,
|
child = AddSICSHdbPar(self->objectNode,
|
||||||
"convertalarm", usSpy, MakeSICSFunc(EpicsConvertAlarm));
|
"convertalarm", usSpy, MakeSICSFunc(EpicsConvertAlarm));
|
||||||
AddSICSHdbPar(child, "stat", usSpy, MakeHdbInt(1.));
|
AddSICSHdbPar(child, "stat", usSpy, MakeHdbInt(1.));
|
||||||
|
|
||||||
AddCommand(pServ->pSics, "epicsadapter", InterInvokeSICSOBJ, KillSICSOBJ, self);
|
AddCommand(pServ->pSics, "epicsadapter", InterInvokeSICSOBJ, KillSICSOBJ, self);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ Mark Koennecke, December 2016
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sics.h>
|
#include <sics.h>
|
||||||
#include <histmem.h>
|
#include <HistMem.h>
|
||||||
#include <sicshipadaba.h>
|
#include <sicshipadaba.h>
|
||||||
|
|
||||||
/*---------------------------------------------------------------*/
|
/*---------------------------------------------------------------*/
|
||||||
|
Reference in New Issue
Block a user