Added new PN_LINK type in link.h, make dbStaticLib display it. Made all device support extended so links can be changed at runtime. Modified startup so add_record() always called before regular link processing. Incomplete, stilll need to add MS/MSS/MSI support, currently disabled.
207 lines
5.4 KiB
C
207 lines
5.4 KiB
C
/*************************************************************************\
|
|
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
|
* National Laboratory.
|
|
* Copyright (c) 2002 The Regents of the University of California, as
|
|
* Operator of Los Alamos National Laboratory.
|
|
* EPICS BASE is distributed subject to a Software License Agreement found
|
|
* in file LICENSE that is included with this distribution.
|
|
\*************************************************************************/
|
|
/* devLiSoftCallback.c */
|
|
/*
|
|
* Authors: Marty Kraimer & Andrew Johnson
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#include "alarm.h"
|
|
#include "callback.h"
|
|
#include "cantProceed.h"
|
|
#include "dbCommon.h"
|
|
#include "dbDefs.h"
|
|
#include "dbAccess.h"
|
|
#include "dbNotify.h"
|
|
#include "recGbl.h"
|
|
#include "recSup.h"
|
|
#include "devSup.h"
|
|
#include "link.h"
|
|
#include "longinRecord.h"
|
|
#include "epicsExport.h"
|
|
|
|
typedef struct notifyInfo {
|
|
processNotify *ppn;
|
|
CALLBACK *pcallback;
|
|
epicsInt32 value;
|
|
int status;
|
|
} notifyInfo;
|
|
|
|
static void getCallback(processNotify *ppn, notifyGetType type)
|
|
{
|
|
longinRecord *prec = (longinRecord *)ppn->usrPvt;
|
|
notifyInfo *pnotifyInfo = (notifyInfo *)prec->dpvt;
|
|
int status = 0;
|
|
long no_elements = 1;
|
|
long options = 0;
|
|
|
|
if (ppn->status == notifyCanceled) {
|
|
printf("devLiSoftCallback::getCallback notifyCanceled\n");
|
|
return;
|
|
}
|
|
|
|
switch (type) {
|
|
case getFieldType:
|
|
status = dbGetField(ppn->paddr, DBR_LONG, &pnotifyInfo->value,
|
|
&options, &no_elements, 0);
|
|
break;
|
|
case getType:
|
|
status = dbGet(ppn->paddr, DBR_LONG, &pnotifyInfo->value,
|
|
&options, &no_elements, 0);
|
|
break;
|
|
}
|
|
pnotifyInfo->status = status;
|
|
}
|
|
|
|
static void doneCallback(processNotify *ppn)
|
|
{
|
|
longinRecord *prec = (longinRecord *)ppn->usrPvt;
|
|
notifyInfo *pnotifyInfo = (notifyInfo *)prec->dpvt;
|
|
|
|
callbackRequestProcessCallback(pnotifyInfo->pcallback, prec->prio, prec);
|
|
}
|
|
|
|
static long add_record(dbCommon *pcommon)
|
|
{
|
|
longinRecord *prec = (longinRecord *)pcommon;
|
|
DBLINK *plink = &prec->inp;
|
|
DBADDR *pdbaddr;
|
|
long status;
|
|
notifyInfo *pnotifyInfo;
|
|
processNotify *ppn;
|
|
|
|
if (plink->type == CONSTANT) return 0;
|
|
|
|
if (plink->type != PV_LINK) {
|
|
recGblRecordError(S_db_badField, (void *)prec,
|
|
"devLiSoftCallback (add_record) Illegal INP field");
|
|
return S_db_badField;
|
|
}
|
|
|
|
pdbaddr = callocMustSucceed(1, sizeof(*pdbaddr),
|
|
"devLiSoftCallback::add_record");
|
|
status = dbNameToAddr(plink->value.pv_link.pvname, pdbaddr);
|
|
if (status) {
|
|
free(pdbaddr);
|
|
recGblRecordError(status, (void *)prec,
|
|
"devLiSoftCallback (init_record) linked record not found");
|
|
return status;
|
|
}
|
|
|
|
plink->type = PN_LINK;
|
|
plink->value.pv_link.precord = pcommon;
|
|
plink->value.pv_link.pvt = pdbaddr;
|
|
plink->value.pv_link.pvlMask = 0;
|
|
|
|
ppn = callocMustSucceed(1, sizeof(*ppn),
|
|
"devLiSoftCallback::add_record");
|
|
ppn->usrPvt = prec;
|
|
ppn->paddr = pdbaddr;
|
|
ppn->getCallback = getCallback;
|
|
ppn->doneCallback = doneCallback;
|
|
ppn->requestType = processGetRequest;
|
|
|
|
pnotifyInfo = callocMustSucceed(1, sizeof(*pnotifyInfo),
|
|
"devLiSoftCallback::add_record");
|
|
pnotifyInfo->pcallback = callocMustSucceed(1, sizeof(CALLBACK),
|
|
"devLiSoftCallback::add_record");
|
|
pnotifyInfo->ppn = ppn;
|
|
|
|
prec->dpvt = pnotifyInfo;
|
|
return 0;
|
|
}
|
|
|
|
static long del_record(dbCommon *pcommon) {
|
|
longinRecord *prec = (longinRecord *)pcommon;
|
|
DBLINK *plink = &prec->inp;
|
|
notifyInfo *pnotifyInfo = (notifyInfo *)prec->dpvt;
|
|
|
|
if (plink->type == CONSTANT) return 0;
|
|
assert (plink->type == PN_LINK);
|
|
|
|
dbNotifyCancel(pnotifyInfo->ppn);
|
|
free(pnotifyInfo->ppn);
|
|
free(pnotifyInfo->pcallback);
|
|
free(pnotifyInfo);
|
|
free(plink->value.pv_link.pvt);
|
|
|
|
plink->type = PV_LINK;
|
|
plink->value.pv_link.pvt = NULL;
|
|
return 0;
|
|
}
|
|
|
|
static struct dsxt dsxtSoftCallback = {
|
|
add_record, del_record
|
|
};
|
|
|
|
static long init(int pass)
|
|
{
|
|
if (pass == 0) devExtend(&dsxtSoftCallback);
|
|
return 0;
|
|
}
|
|
|
|
static long init_record(longinRecord *prec)
|
|
{
|
|
/* INP must be CONSTANT or PN_LINK */
|
|
switch (prec->inp.type) {
|
|
case CONSTANT:
|
|
if (recGblInitConstantLink(&prec->inp, DBR_LONG, &prec->val))
|
|
prec->udf = FALSE;
|
|
break;
|
|
case PN_LINK:
|
|
/* Handled by add_record */
|
|
break;
|
|
default:
|
|
recGblRecordError(S_db_badField, (void *)prec,
|
|
"devLiSoftCallback (init_record) Illegal INP field");
|
|
prec->pact = TRUE;
|
|
return S_db_badField;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static long read_li(longinRecord *prec)
|
|
{
|
|
notifyInfo *pnotifyInfo = (notifyInfo *)prec->dpvt;
|
|
|
|
if (!prec->dpvt)
|
|
return 0;
|
|
|
|
if (!prec->pact) {
|
|
dbProcessNotify(pnotifyInfo->ppn);
|
|
prec->pact = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
if (pnotifyInfo->status) {
|
|
recGblSetSevr(prec, READ_ALARM, INVALID_ALARM);
|
|
return pnotifyInfo->status;
|
|
}
|
|
|
|
prec->val = pnotifyInfo->value;
|
|
prec->udf = FALSE;
|
|
|
|
if (prec->tsel.type == CONSTANT &&
|
|
prec->tse == epicsTimeEventDeviceTime)
|
|
prec->time = prec->inp.value.pv_link.precord->time;
|
|
return 0;
|
|
}
|
|
|
|
/* Create the dset for devLiSoftCallback */
|
|
struct {
|
|
dset common;
|
|
DEVSUPFUN read_li;
|
|
} devLiSoftCallback = {
|
|
{5, NULL, init, init_record, NULL},
|
|
read_li
|
|
};
|
|
epicsExportAddress(dset, devLiSoftCallback);
|