/*************************************************************************\ * 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 #include #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);