Files
pcas/src/std/dev/devSiSoftCallback.c
Andrew Johnson e6149b6606 Merged process-get branch.
Seems to work, but not tested in depth.
2012-07-11 18:07:23 -05:00

226 lines
5.7 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.
\*************************************************************************/
/* devSiSoftCallback.c */
/*
* Authors: Marty Kraimer & Andrew Johnson
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "callback.h"
#include "cantProceed.h"
#include "dbCommon.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "dbChannel.h"
#include "dbNotify.h"
#include "epicsAssert.h"
#include "recGbl.h"
#include "recSup.h"
#include "devSup.h"
#include "link.h"
#include "stringinRecord.h"
#include "epicsExport.h"
#define GET_OPTIONS (DBR_STATUS | DBR_TIME)
typedef struct devPvt {
DBADDR dbaddr;
processNotify pn;
CALLBACK callback;
long options;
int status;
struct {
DBRstatus
DBRtime
char value[MAX_STRING_SIZE];
} buffer;
} devPvt;
static void getCallback(processNotify *ppn, notifyGetType type)
{
stringinRecord *prec = (stringinRecord *)ppn->usrPvt;
devPvt *pdevPvt = (devPvt *)prec->dpvt;
long no_elements = 1;
if (ppn->status==notifyCanceled) {
printf("devSiSoftCallback::getCallback notifyCanceled\n");
return;
}
assert(type == getFieldType);
pdevPvt->status = dbChannelGetField(ppn->chan, DBR_STRING,
&pdevPvt->buffer, &pdevPvt->options, &no_elements, 0);
}
static void doneCallback(processNotify *ppn)
{
stringinRecord *prec = (stringinRecord *)ppn->usrPvt;
devPvt *pdevPvt = (devPvt *)prec->dpvt;
callbackRequestProcessCallback(&pdevPvt->callback, prec->prio, prec);
}
static long add_record(dbCommon *pcommon)
{
stringinRecord *prec = (stringinRecord *)pcommon;
DBLINK *plink = &prec->inp;
dbChannel *chan;
devPvt *pdevPvt;
processNotify *ppn;
if (plink->type == CONSTANT) return 0;
if (plink->type != PV_LINK) {
long status = S_db_badField;
recGblRecordError(status, (void *)prec,
"devSiSoftCallback (add_record) Illegal INP field");
return status;
}
pdevPvt = calloc(1, sizeof(*pdevPvt));
if (!pdevPvt) {
long status = S_db_noMemory;
recGblRecordError(status, (void *)prec,
"devSiSoftCallback (add_record) out of memory, calloc() failed");
return status;
}
ppn = &pdevPvt->pn;
chan = dbChannelCreate(plink->value.pv_link.pvname);
if (!chan) {
long status = S_db_notFound;
recGblRecordError(status, (void *)prec,
"devSiSoftCallback (add_record) linked record not found");
return status;
}
plink->type = PN_LINK;
plink->value.pv_link.precord = pcommon;
plink->value.pv_link.pvlMask &= pvlOptMsMode; /* Severity flags only */
ppn->usrPvt = prec;
ppn->chan = chan;
ppn->getCallback = getCallback;
ppn->doneCallback = doneCallback;
ppn->requestType = processGetRequest;
pdevPvt->options = GET_OPTIONS;
prec->dpvt = pdevPvt;
return 0;
}
static long del_record(dbCommon *pcommon) {
stringinRecord *prec = (stringinRecord *)pcommon;
DBLINK *plink = &prec->inp;
devPvt *pdevPvt = (devPvt *)prec->dpvt;
if (plink->type == CONSTANT) return 0;
assert(plink->type == PN_LINK);
dbNotifyCancel(&pdevPvt->pn);
dbChannelDelete(pdevPvt->pn.chan);
free(pdevPvt);
plink->type = PV_LINK;
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(stringinRecord *prec)
{
/* INP must be CONSTANT or PN_LINK */
switch (prec->inp.type) {
case CONSTANT:
if (recGblInitConstantLink(&prec->inp, DBR_STRING, &prec->val))
prec->udf = FALSE;
break;
case PN_LINK:
/* Handled by add_record */
break;
default:
recGblRecordError(S_db_badField, (void *)prec,
"devSiSoftCallback (init_record) Illegal INP field");
prec->pact = TRUE;
return S_db_badField;
}
return 0;
}
static long read_si(stringinRecord *prec)
{
devPvt *pdevPvt = (devPvt *)prec->dpvt;
if (!prec->dpvt)
return 0;
if (!prec->pact) {
dbProcessNotify(&pdevPvt->pn);
prec->pact = TRUE;
return 0;
}
if (pdevPvt->status) {
recGblSetSevr(prec, READ_ALARM, INVALID_ALARM);
return pdevPvt->status;
}
strncpy(prec->val, pdevPvt->buffer.value, MAX_STRING_SIZE);
prec->val[MAX_STRING_SIZE-1] = 0;
prec->udf = FALSE;
switch (prec->inp.value.pv_link.pvlMask & pvlOptMsMode) {
case pvlOptNMS:
break;
case pvlOptMSI:
if (pdevPvt->buffer.severity < INVALID_ALARM)
break;
/* else fall through */
case pvlOptMS:
recGblSetSevr(prec, LINK_ALARM, pdevPvt->buffer.severity);
break;
case pvlOptMSS:
recGblSetSevr(prec, pdevPvt->buffer.status,
pdevPvt->buffer.severity);
break;
}
if (prec->tsel.type == CONSTANT &&
prec->tse == epicsTimeEventDeviceTime)
prec->time = pdevPvt->buffer.time;
return 0;
}
/* Create the dset for devSiSoftCallback */
struct {
dset common;
DEVSUPFUN read_li;
} devSiSoftCallback = {
{5, NULL, init, init_record, NULL},
read_si
};
epicsExportAddress(dset,devSiSoftCallback);