Merged process-get branch.
Seems to work, but not tested in depth.
This commit is contained in:
@@ -983,10 +983,10 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
dbRemoveLink(plink);
|
||||
break;
|
||||
|
||||
case PV_LINK:
|
||||
case CONSTANT:
|
||||
break; /* do nothing */
|
||||
|
||||
case PV_LINK:
|
||||
case MACRO_LINK:
|
||||
break; /* should never get here */
|
||||
|
||||
@@ -1031,7 +1031,7 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
break;
|
||||
|
||||
case CONSTANT:
|
||||
break;
|
||||
break; /* do nothing */
|
||||
|
||||
case DB_LINK:
|
||||
case CA_LINK:
|
||||
|
||||
+2
-1
@@ -55,7 +55,8 @@
|
||||
#include "db_convert.h"
|
||||
#include "resourceLib.h"
|
||||
|
||||
extern "C" void putNotifyCompletion ( putNotify *ppn );
|
||||
extern "C" int putNotifyPut ( processNotify *ppn, notifyPutType notifyPutType );
|
||||
extern "C" void putNotifyCompletion ( processNotify *ppn );
|
||||
|
||||
class dbContext;
|
||||
class dbChannelIO;
|
||||
|
||||
@@ -171,16 +171,16 @@
|
||||
extra("struct asgMember *asp")
|
||||
}
|
||||
field(PPN,DBF_NOACCESS) {
|
||||
prompt("addr of PUTNOTIFY")
|
||||
prompt("pprocessNotify")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("struct putNotify *ppn")
|
||||
extra("struct processNotify *ppn")
|
||||
}
|
||||
field(PPNR,DBF_NOACCESS) {
|
||||
prompt("pputNotifyRecord")
|
||||
prompt("pprocessNotifyRecord")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("struct putNotifyRecord *ppnr")
|
||||
extra("struct processNotifyRecord *ppnr")
|
||||
}
|
||||
field(SPVT,DBF_NOACCESS) {
|
||||
prompt("Scan Private")
|
||||
|
||||
+348
-255
@@ -1,10 +1,9 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* Copyright (c) 2012 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 Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
@@ -47,39 +46,39 @@
|
||||
#include "epicsTime.h"
|
||||
#include "cantProceed.h"
|
||||
|
||||
/*putNotify.state values */
|
||||
/*notify state values */
|
||||
typedef enum {
|
||||
putNotifyNotActive,
|
||||
putNotifyWaitForRestart,
|
||||
putNotifyRestartCallbackRequested,
|
||||
putNotifyRestartInProgress,
|
||||
putNotifyPutInProgress,
|
||||
putNotifyUserCallbackRequested,
|
||||
putNotifyUserCallbackActive
|
||||
} putNotifyState;
|
||||
notifyNotActive,
|
||||
notifyWaitForRestart,
|
||||
notifyRestartCallbackRequested,
|
||||
notifyRestartInProgress,
|
||||
notifyProcessInProgress,
|
||||
notifyUserCallbackRequested,
|
||||
notifyUserCallbackActive
|
||||
} notifyState;
|
||||
|
||||
/*structure attached to ppnr field of each record*/
|
||||
typedef struct putNotifyRecord {
|
||||
typedef struct processNotifyRecord {
|
||||
ellCheckNode waitNode;
|
||||
ELLLIST restartList; /*list of putNotifys to restart*/
|
||||
ELLLIST restartList; /*list of processNotifys to restart*/
|
||||
dbCommon *precord;
|
||||
} putNotifyRecord;
|
||||
} processNotifyRecord;
|
||||
|
||||
#define MAGIC 0xfedc0123
|
||||
typedef struct putNotifyPvt {
|
||||
ELLNODE node; /*For free list*/
|
||||
long magic;
|
||||
short state;
|
||||
CALLBACK callback;
|
||||
ELLLIST waitList; /*list of records for current putNotify*/
|
||||
short cancelWait;
|
||||
short userCallbackWait;
|
||||
typedef struct notifyPvt {
|
||||
ELLNODE node; /*For free list*/
|
||||
long magic;
|
||||
short state;
|
||||
CALLBACK callback;
|
||||
ELLLIST waitList; /*list of records for current processNotify*/
|
||||
short cancelWait;
|
||||
short userCallbackWait;
|
||||
epicsEventId cancelEvent;
|
||||
epicsEventId userCallbackEvent;
|
||||
} putNotifyPvt;
|
||||
} notifyPvt;
|
||||
|
||||
/* putNotify groups can span locksets if links are dynamically modified*/
|
||||
/* Thus a global lock is taken while putNotify fields are accessed */
|
||||
/* processNotify groups can span locksets if links are dynamically modified*/
|
||||
/* Thus a global lock is taken while processNotify fields are accessed */
|
||||
typedef struct notifyGlobal {
|
||||
epicsMutexId lock;
|
||||
ELLLIST freeList;
|
||||
@@ -88,12 +87,12 @@ typedef struct notifyGlobal {
|
||||
static notifyGlobal *pnotifyGlobal = 0;
|
||||
|
||||
/*Local routines*/
|
||||
static void putNotifyInit(putNotify *ppn);
|
||||
static void putNotifyCleanup(putNotify *ppn);
|
||||
static void restartCheck(putNotifyRecord *ppnr);
|
||||
static void callUser(dbCommon *precord, putNotify *ppn);
|
||||
static void notifyInit(processNotify *ppn);
|
||||
static void notifyCleanup(processNotify *ppn);
|
||||
static void restartCheck(processNotifyRecord *ppnr);
|
||||
static void callDone(dbCommon *precord,processNotify *ppn);
|
||||
static void processNotifyCommon(processNotify *ppn,dbCommon *precord);
|
||||
static void notifyCallback(CALLBACK *pcallback);
|
||||
static void putNotifyCommon(putNotify *ppn, dbCommon *precord);
|
||||
|
||||
#define ellSafeAdd(list,listnode) \
|
||||
{ \
|
||||
@@ -109,175 +108,197 @@ static void putNotifyCommon(putNotify *ppn, dbCommon *precord);
|
||||
(listnode)->isOnList=0; \
|
||||
}
|
||||
|
||||
static void putNotifyInit(putNotify *ppn)
|
||||
static void notifyInit(processNotify *ppn)
|
||||
{
|
||||
putNotifyPvt *pputNotifyPvt;
|
||||
notifyPvt *pnotifyPvt;
|
||||
|
||||
pputNotifyPvt = (putNotifyPvt *) ellFirst(&pnotifyGlobal->freeList);
|
||||
if (pputNotifyPvt) {
|
||||
ellDelete(&pnotifyGlobal->freeList, &pputNotifyPvt->node);
|
||||
pnotifyPvt = (notifyPvt *) ellFirst(&pnotifyGlobal->freeList);
|
||||
if (pnotifyPvt) {
|
||||
ellDelete(&pnotifyGlobal->freeList, &pnotifyPvt->node);
|
||||
} else {
|
||||
pputNotifyPvt = dbCalloc(1,sizeof(putNotifyPvt));
|
||||
pputNotifyPvt->cancelEvent = epicsEventCreate(epicsEventEmpty);
|
||||
pputNotifyPvt->userCallbackEvent = epicsEventCreate(epicsEventEmpty);
|
||||
pputNotifyPvt->magic = MAGIC;
|
||||
pputNotifyPvt->state = putNotifyNotActive;
|
||||
pnotifyPvt = dbCalloc(1,sizeof(notifyPvt));
|
||||
pnotifyPvt->cancelEvent = epicsEventCreate(epicsEventEmpty);
|
||||
pnotifyPvt->userCallbackEvent = epicsEventCreate(epicsEventEmpty);
|
||||
pnotifyPvt->magic = MAGIC;
|
||||
pnotifyPvt->state = notifyNotActive;
|
||||
}
|
||||
pputNotifyPvt->state = putNotifyNotActive;
|
||||
callbackSetCallback(notifyCallback,&pputNotifyPvt->callback);
|
||||
callbackSetUser(ppn,&pputNotifyPvt->callback);
|
||||
callbackSetPriority(priorityLow,&pputNotifyPvt->callback);
|
||||
ellInit(&pputNotifyPvt->waitList);
|
||||
ppn->status = 0;
|
||||
pputNotifyPvt->state = putNotifyNotActive;
|
||||
pputNotifyPvt->cancelWait = pputNotifyPvt->userCallbackWait = 0;
|
||||
ppn->pputNotifyPvt = pputNotifyPvt;
|
||||
pnotifyPvt->state = notifyNotActive;
|
||||
callbackSetCallback(notifyCallback,&pnotifyPvt->callback);
|
||||
callbackSetUser(ppn,&pnotifyPvt->callback);
|
||||
callbackSetPriority(priorityLow,&pnotifyPvt->callback);
|
||||
ellInit(&pnotifyPvt->waitList);
|
||||
ppn->status = notifyOK;
|
||||
ppn->wasProcessed = 0;
|
||||
pnotifyPvt->state = notifyNotActive;
|
||||
pnotifyPvt->cancelWait = pnotifyPvt->userCallbackWait = 0;
|
||||
ppn->pnotifyPvt = pnotifyPvt;
|
||||
}
|
||||
|
||||
static void putNotifyCleanup(putNotify *ppn)
|
||||
static void notifyCleanup(processNotify *ppn)
|
||||
{
|
||||
putNotifyPvt *pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
|
||||
notifyPvt *pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
|
||||
|
||||
pputNotifyPvt->state = putNotifyNotActive;
|
||||
ellAdd(&pnotifyGlobal->freeList, &pputNotifyPvt->node);
|
||||
ppn->pputNotifyPvt = 0;
|
||||
pnotifyPvt->state = notifyNotActive;
|
||||
ellAdd(&pnotifyGlobal->freeList, &pnotifyPvt->node);
|
||||
ppn->pnotifyPvt = 0;
|
||||
}
|
||||
|
||||
static void restartCheck(putNotifyRecord *ppnr)
|
||||
static void restartCheck(processNotifyRecord *ppnr)
|
||||
{
|
||||
dbCommon *precord = ppnr->precord;
|
||||
putNotify *pfirst;
|
||||
putNotifyPvt *pputNotifyPvt;
|
||||
|
||||
processNotify *pfirst;
|
||||
notifyPvt *pnotifyPvt;
|
||||
|
||||
assert(precord->ppn);
|
||||
pfirst = (putNotify *) ellFirst(&ppnr->restartList);
|
||||
pfirst = (processNotify *) ellFirst(&ppnr->restartList);
|
||||
if (!pfirst) {
|
||||
precord->ppn = 0;
|
||||
return;
|
||||
}
|
||||
pputNotifyPvt = (putNotifyPvt *) pfirst->pputNotifyPvt;
|
||||
assert(pputNotifyPvt->state==putNotifyWaitForRestart);
|
||||
pnotifyPvt = (notifyPvt *) pfirst->pnotifyPvt;
|
||||
assert(pnotifyPvt->state == notifyWaitForRestart);
|
||||
/* remove pfirst from restartList */
|
||||
ellSafeDelete(&ppnr->restartList,&pfirst->restartNode);
|
||||
ellSafeDelete(&ppnr->restartList, &pfirst->restartNode);
|
||||
/*make pfirst owner of the record*/
|
||||
precord->ppn = pfirst;
|
||||
/* request callback for pfirst */
|
||||
pputNotifyPvt->state = putNotifyRestartCallbackRequested;
|
||||
callbackRequest(&pputNotifyPvt->callback);
|
||||
pnotifyPvt->state = notifyRestartCallbackRequested;
|
||||
callbackRequest(&pnotifyPvt->callback);
|
||||
}
|
||||
|
||||
static void callUser(dbCommon *precord, putNotify *ppn)
|
||||
static void callDone(dbCommon *precord, processNotify *ppn)
|
||||
{
|
||||
putNotifyPvt *pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
|
||||
notifyPvt *pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
|
||||
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
if (ppn->requestType == processGetRequest ||
|
||||
ppn->requestType == putProcessGetRequest) {
|
||||
ppn->getCallback(ppn, getFieldType);
|
||||
}
|
||||
dbScanUnlock(precord);
|
||||
(*ppn->userCallback)(ppn);
|
||||
ppn->doneCallback(ppn);
|
||||
epicsMutexMustLock(pnotifyGlobal->lock);
|
||||
if (pputNotifyPvt->cancelWait && pputNotifyPvt->userCallbackWait) {
|
||||
errlogPrintf("%s putNotify: both cancelWait and userCallbackWait true."
|
||||
"This is illegal\n", precord->name);
|
||||
pputNotifyPvt->cancelWait = pputNotifyPvt->userCallbackWait = 0;
|
||||
if (pnotifyPvt->cancelWait && pnotifyPvt->userCallbackWait) {
|
||||
errlogPrintf("%s processNotify: both cancelWait and userCallbackWait true."
|
||||
"This is illegal\n", precord->name);
|
||||
pnotifyPvt->cancelWait = pnotifyPvt->userCallbackWait = 0;
|
||||
}
|
||||
if (!pputNotifyPvt->cancelWait && !pputNotifyPvt->userCallbackWait) {
|
||||
putNotifyCleanup(ppn);
|
||||
if (!pnotifyPvt->cancelWait && !pnotifyPvt->userCallbackWait) {
|
||||
notifyCleanup(ppn);
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
return;
|
||||
}
|
||||
if (pnotifyPvt->cancelWait) {
|
||||
pnotifyPvt->cancelWait = 0;
|
||||
epicsEventSignal(pnotifyPvt->cancelEvent);
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
return;
|
||||
}
|
||||
if (pputNotifyPvt->cancelWait) {
|
||||
pputNotifyPvt->cancelWait = 0;
|
||||
epicsEventSignal(pputNotifyPvt->cancelEvent);
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
return;
|
||||
}
|
||||
assert(pputNotifyPvt->userCallbackWait);
|
||||
pputNotifyPvt->userCallbackWait = 0;
|
||||
epicsEventSignal(pputNotifyPvt->userCallbackEvent);
|
||||
assert(pnotifyPvt->userCallbackWait);
|
||||
pnotifyPvt->userCallbackWait = 0;
|
||||
epicsEventSignal(pnotifyPvt->userCallbackEvent);
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
static void putNotifyCommon(putNotify *ppn, dbCommon *precord)
|
||||
static void processNotifyCommon(processNotify *ppn,dbCommon *precord)
|
||||
{
|
||||
long status;
|
||||
putNotifyPvt *pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
|
||||
notifyPvt *pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
|
||||
int didPut = 0;
|
||||
int doProcess = 0;
|
||||
|
||||
if (precord->ppn &&
|
||||
pputNotifyPvt->state != putNotifyRestartCallbackRequested) { /*another putNotify owns the record */
|
||||
pputNotifyPvt->state = putNotifyWaitForRestart;
|
||||
ellSafeAdd(&precord->ppnr->restartList,&ppn->restartNode);
|
||||
pnotifyPvt->state != notifyRestartCallbackRequested) {
|
||||
/* Another processNotify owns the record */
|
||||
pnotifyPvt->state = notifyWaitForRestart;
|
||||
ellSafeAdd(&precord->ppnr->restartList, &ppn->restartNode);
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
dbScanUnlock(precord);
|
||||
return;
|
||||
} else if (precord->ppn) {
|
||||
assert(precord->ppn == ppn);
|
||||
assert(pputNotifyPvt->state==putNotifyRestartCallbackRequested);
|
||||
assert(pnotifyPvt->state == notifyRestartCallbackRequested);
|
||||
}
|
||||
if (precord->pact) {
|
||||
precord->ppn = ppn;
|
||||
ellSafeAdd(&pputNotifyPvt->waitList,&precord->ppnr->waitNode);
|
||||
pputNotifyPvt->state = putNotifyRestartInProgress;
|
||||
ellSafeAdd(&pnotifyPvt->waitList, &precord->ppnr->waitNode);
|
||||
pnotifyPvt->state = notifyRestartInProgress;
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
dbScanUnlock(precord);
|
||||
return;
|
||||
}
|
||||
status = dbChannelPut(ppn->chan, ppn->dbrType, ppn->pbuffer, ppn->nRequest);
|
||||
ppn->status = (status == 0) ? putNotifyOK : putNotifyError;
|
||||
/* Check to see if dbProcess should not be called */
|
||||
if (!status /*dont process if dbPut returned error */
|
||||
&& ((dbChannelField(ppn->chan) == (void *) & precord->proc) /*If PROC call dbProcess*/
|
||||
|| (dbChannelFldDes(ppn->chan)->process_passive && precord->scan == 0))) {
|
||||
if (ppn->requestType == putProcessRequest ||
|
||||
ppn->requestType == putProcessGetRequest) {
|
||||
/* Check if puts disabled */
|
||||
if (precord->disp && (dbChannelField(ppn->chan) != (void *) &precord->disp)) {
|
||||
ppn->putCallback(ppn, putDisabledType);
|
||||
} else {
|
||||
didPut = ppn->putCallback(ppn, putType);
|
||||
}
|
||||
}
|
||||
/* Check if dbProcess should be called */
|
||||
if (didPut &&
|
||||
((dbChannelField(ppn->chan) == (void *) &precord->proc) ||
|
||||
(dbChannelFldDes(ppn->chan)->process_passive && precord->scan == 0)))
|
||||
doProcess = 1;
|
||||
else
|
||||
if (ppn->requestType == processGetRequest &&
|
||||
precord->scan == 0)
|
||||
doProcess = 1;
|
||||
|
||||
if (doProcess) {
|
||||
ppn->wasProcessed = 1;
|
||||
precord->ppn = ppn;
|
||||
ellSafeAdd(&pputNotifyPvt->waitList,&precord->ppnr->waitNode);
|
||||
pputNotifyPvt->state = putNotifyPutInProgress;
|
||||
ellSafeAdd(&pnotifyPvt->waitList, &precord->ppnr->waitNode);
|
||||
pnotifyPvt->state = notifyProcessInProgress;
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
dbProcess(precord);
|
||||
dbScanUnlock(precord);
|
||||
return;
|
||||
}
|
||||
if (pputNotifyPvt->state == putNotifyRestartCallbackRequested) {
|
||||
if (pnotifyPvt->state == notifyRestartCallbackRequested) {
|
||||
restartCheck(precord->ppnr);
|
||||
}
|
||||
pputNotifyPvt->state = putNotifyUserCallbackActive;
|
||||
pnotifyPvt->state = notifyUserCallbackActive;
|
||||
assert(precord->ppn!=ppn);
|
||||
callUser(precord, ppn);
|
||||
callDone(precord, ppn);
|
||||
}
|
||||
|
||||
static void notifyCallback(CALLBACK *pcallback)
|
||||
{
|
||||
putNotify *ppn = NULL;
|
||||
dbCommon *precord;
|
||||
putNotifyPvt *pputNotifyPvt;
|
||||
processNotify *ppn = NULL;
|
||||
dbCommon *precord;
|
||||
notifyPvt *pnotifyPvt;
|
||||
|
||||
callbackGetUser(ppn,pcallback);
|
||||
pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
|
||||
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
|
||||
precord = dbChannelRecord(ppn->chan);
|
||||
dbScanLock(precord);
|
||||
epicsMutexMustLock(pnotifyGlobal->lock);
|
||||
assert(precord->ppnr);
|
||||
assert(pputNotifyPvt->state==putNotifyRestartCallbackRequested
|
||||
|| pputNotifyPvt->state==putNotifyUserCallbackRequested);
|
||||
assert(ellCount(&pputNotifyPvt->waitList)==0);
|
||||
if (pputNotifyPvt->cancelWait) {
|
||||
if (pputNotifyPvt->state == putNotifyRestartCallbackRequested) {
|
||||
assert(pnotifyPvt->state == notifyRestartCallbackRequested ||
|
||||
pnotifyPvt->state == notifyUserCallbackRequested);
|
||||
assert(ellCount(&pnotifyPvt->waitList) == 0);
|
||||
if (pnotifyPvt->cancelWait) {
|
||||
if (pnotifyPvt->state == notifyRestartCallbackRequested) {
|
||||
restartCheck(precord->ppnr);
|
||||
}
|
||||
epicsEventSignal(pputNotifyPvt->cancelEvent);
|
||||
epicsEventSignal(pnotifyPvt->cancelEvent);
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
dbScanUnlock(precord);
|
||||
return;
|
||||
}
|
||||
if (pputNotifyPvt->state == putNotifyRestartCallbackRequested) {
|
||||
putNotifyCommon(ppn, precord);
|
||||
if(pnotifyPvt->state == notifyRestartCallbackRequested) {
|
||||
processNotifyCommon(ppn, precord);
|
||||
return;
|
||||
}
|
||||
/* All done. Clean up and call userCallback */
|
||||
pputNotifyPvt->state = putNotifyUserCallbackActive;
|
||||
pnotifyPvt->state = notifyUserCallbackActive;
|
||||
assert(precord->ppn!=ppn);
|
||||
callUser(precord, ppn);
|
||||
callDone(precord, ppn);
|
||||
}
|
||||
|
||||
void epicsShareAPI dbPutNotifyInit(void)
|
||||
void epicsShareAPI dbProcessNotifyInit(void)
|
||||
{
|
||||
if (pnotifyGlobal)
|
||||
return;
|
||||
@@ -286,146 +307,153 @@ void epicsShareAPI dbPutNotifyInit(void)
|
||||
ellInit(&pnotifyGlobal->freeList);
|
||||
}
|
||||
|
||||
void epicsShareAPI dbPutNotify(putNotify *ppn)
|
||||
void epicsShareAPI dbProcessNotify(processNotify *ppn)
|
||||
{
|
||||
struct dbChannel *chan = ppn->chan;
|
||||
dbCommon *precord = dbChannelRecord(chan);
|
||||
short dbfType = dbChannelFieldType(chan);
|
||||
long status = 0;
|
||||
putNotifyPvt *pputNotifyPvt;
|
||||
notifyPvt *pnotifyPvt;
|
||||
|
||||
assert(precord);
|
||||
/*check for putField disabled*/
|
||||
if (precord->disp) {
|
||||
if (dbChannelField(chan) != (void *) & precord->disp) {
|
||||
ppn->status = putNotifyPutDisabled;
|
||||
(*ppn->userCallback)(ppn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Must handle DBF_XXXLINKs as special case.
|
||||
* Only dbPutField will change link fields.
|
||||
* Also the record is not processed as a result
|
||||
*/
|
||||
if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
|
||||
status = dbChannelPutField(ppn->chan, ppn->dbrType, ppn->pbuffer,
|
||||
ppn->nRequest);
|
||||
ppn->status = (status == 0) ? putNotifyOK : putNotifyError;
|
||||
(*ppn->userCallback)(ppn);
|
||||
*/
|
||||
ppn->status = notifyOK;
|
||||
ppn->wasProcessed = 0;
|
||||
if (dbfType>=DBF_INLINK && dbfType<=DBF_FWDLINK) {
|
||||
if (ppn->requestType == putProcessRequest ||
|
||||
ppn->requestType == putProcessGetRequest) {
|
||||
/* Check if puts disabled */
|
||||
if (precord->disp && (dbChannelField(ppn->chan) != (void *) &precord->disp)) {
|
||||
ppn->putCallback(ppn, putDisabledType);
|
||||
} else {
|
||||
ppn->putCallback(ppn, putFieldType);
|
||||
}
|
||||
}
|
||||
if (ppn->requestType == processGetRequest ||
|
||||
ppn->requestType == putProcessGetRequest) {
|
||||
ppn->getCallback(ppn, getFieldType);
|
||||
|
||||
}
|
||||
ppn->doneCallback(ppn);
|
||||
return;
|
||||
}
|
||||
dbScanLock(precord);
|
||||
epicsMutexMustLock(pnotifyGlobal->lock);
|
||||
pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
|
||||
if (pputNotifyPvt && (pputNotifyPvt->magic != MAGIC)) {
|
||||
printf("dbPutNotify:pputNotifyPvt was not initialized\n");
|
||||
pputNotifyPvt = 0;
|
||||
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
|
||||
if (pnotifyPvt && (pnotifyPvt->magic != MAGIC)) {
|
||||
printf("dbPutNotify:pnotifyPvt was not initialized\n");
|
||||
pnotifyPvt = 0;
|
||||
}
|
||||
if (pputNotifyPvt) {
|
||||
assert(pputNotifyPvt->state==putNotifyUserCallbackActive);
|
||||
pputNotifyPvt->userCallbackWait = 1;
|
||||
if (pnotifyPvt) {
|
||||
assert(pnotifyPvt->state == notifyUserCallbackActive);
|
||||
pnotifyPvt->userCallbackWait = 1;
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
dbScanUnlock(precord);
|
||||
epicsEventWait(pputNotifyPvt->userCallbackEvent);
|
||||
epicsEventWait(pnotifyPvt->userCallbackEvent);
|
||||
dbScanLock(precord);
|
||||
epicsMutexMustLock(pnotifyGlobal->lock);
|
||||
putNotifyCleanup(ppn);
|
||||
notifyCleanup(ppn);
|
||||
}
|
||||
pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
|
||||
assert(!pputNotifyPvt);
|
||||
putNotifyInit(ppn);
|
||||
pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
|
||||
if (!precord->ppnr) {/* make sure record has a putNotifyRecord*/
|
||||
precord->ppnr = dbCalloc(1,sizeof(putNotifyRecord));
|
||||
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
|
||||
assert(!pnotifyPvt);
|
||||
notifyInit(ppn);
|
||||
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
|
||||
if (!precord->ppnr) {
|
||||
/* make sure record has a processNotifyRecord*/
|
||||
precord->ppnr = dbCalloc(1, sizeof(processNotifyRecord));
|
||||
precord->ppnr->precord = precord;
|
||||
ellInit(&precord->ppnr->restartList);
|
||||
}
|
||||
putNotifyCommon(ppn, precord);
|
||||
processNotifyCommon(ppn, precord);
|
||||
}
|
||||
|
||||
void epicsShareAPI dbNotifyCancel(putNotify *ppn)
|
||||
void epicsShareAPI dbNotifyCancel(processNotify *ppn)
|
||||
{
|
||||
dbCommon *precord = dbChannelRecord(ppn->chan);
|
||||
putNotifyState state;
|
||||
putNotifyPvt *pputNotifyPvt;
|
||||
notifyState state;
|
||||
notifyPvt *pnotifyPvt;
|
||||
|
||||
assert(precord);
|
||||
dbScanLock(precord);
|
||||
epicsMutexMustLock(pnotifyGlobal->lock);
|
||||
pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
|
||||
if (!pputNotifyPvt || pputNotifyPvt->state == putNotifyNotActive) {
|
||||
ppn->status = notifyCanceled;
|
||||
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
|
||||
if (!pnotifyPvt || pnotifyPvt->state == notifyNotActive) {
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
dbScanUnlock(precord);
|
||||
return;
|
||||
}
|
||||
state = pputNotifyPvt->state;
|
||||
/*If callback is scheduled or active wait for it to complete*/
|
||||
if (state == putNotifyUserCallbackRequested || state
|
||||
== putNotifyRestartCallbackRequested || state
|
||||
== putNotifyUserCallbackActive) {
|
||||
pputNotifyPvt->cancelWait = 1;
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
dbScanUnlock(precord);
|
||||
epicsEventWait(pputNotifyPvt->cancelEvent);
|
||||
epicsMutexMustLock(pnotifyGlobal->lock);
|
||||
putNotifyCleanup(ppn);
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
state = pnotifyPvt->state;
|
||||
switch (state) {
|
||||
case putNotifyNotActive:
|
||||
break;
|
||||
case putNotifyWaitForRestart:
|
||||
case notifyUserCallbackRequested:
|
||||
case notifyRestartCallbackRequested:
|
||||
case notifyUserCallbackActive:
|
||||
/* Callback is scheduled or active, wait for it to complete */
|
||||
pnotifyPvt->cancelWait = 1;
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
dbScanUnlock(precord);
|
||||
epicsEventWait(pnotifyPvt->cancelEvent);
|
||||
epicsMutexMustLock(pnotifyGlobal->lock);
|
||||
notifyCleanup(ppn);
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
return;
|
||||
case notifyNotActive:
|
||||
break;
|
||||
case notifyWaitForRestart:
|
||||
assert(precord->ppn);
|
||||
assert(precord->ppn!=ppn);
|
||||
ellSafeDelete(&precord->ppnr->restartList,&ppn->restartNode)
|
||||
;
|
||||
ellSafeDelete(&precord->ppnr->restartList,&ppn->restartNode);
|
||||
break;
|
||||
case putNotifyRestartInProgress:
|
||||
case putNotifyPutInProgress: { /*Take all records out of wait list */
|
||||
putNotifyRecord *ppnrWait;
|
||||
case notifyRestartInProgress:
|
||||
case notifyProcessInProgress:
|
||||
{ /*Take all records out of wait list */
|
||||
processNotifyRecord *ppnrWait;
|
||||
|
||||
while ((ppnrWait = (putNotifyRecord *) ellFirst(&pputNotifyPvt->waitList))) {
|
||||
ellSafeDelete(&pputNotifyPvt->waitList,&ppnrWait->waitNode);
|
||||
restartCheck(ppnrWait);
|
||||
while ((ppnrWait = (processNotifyRecord *)
|
||||
ellFirst(&pnotifyPvt->waitList))) {
|
||||
ellSafeDelete(&pnotifyPvt->waitList, &ppnrWait->waitNode);
|
||||
restartCheck(ppnrWait);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (precord->ppn == ppn)
|
||||
restartCheck(precord->ppnr);
|
||||
break;
|
||||
default:
|
||||
printf("dbNotify: illegal state for notifyCallback\n");
|
||||
}
|
||||
pputNotifyPvt->state = putNotifyNotActive;
|
||||
putNotifyCleanup(ppn);
|
||||
pnotifyPvt->state = notifyNotActive;
|
||||
notifyCleanup(ppn);
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
dbScanUnlock(precord);
|
||||
}
|
||||
|
||||
void epicsShareAPI dbNotifyCompletion(dbCommon *precord)
|
||||
{
|
||||
putNotify *ppn = precord->ppn;
|
||||
putNotifyPvt *pputNotifyPvt;
|
||||
processNotify *ppn = precord->ppn;
|
||||
notifyPvt *pnotifyPvt;
|
||||
|
||||
epicsMutexMustLock(pnotifyGlobal->lock);
|
||||
assert(ppn);
|
||||
assert(precord->ppnr);
|
||||
pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
|
||||
if (pputNotifyPvt->state != putNotifyRestartInProgress
|
||||
&& pputNotifyPvt->state != putNotifyPutInProgress) {
|
||||
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
|
||||
if (pnotifyPvt->state != notifyRestartInProgress &&
|
||||
pnotifyPvt->state != notifyProcessInProgress) {
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
return;
|
||||
}
|
||||
ellSafeDelete(&pputNotifyPvt->waitList,&precord->ppnr->waitNode);
|
||||
if ((ellCount(&pputNotifyPvt->waitList)!=0)) {
|
||||
ellSafeDelete(&pnotifyPvt->waitList, &precord->ppnr->waitNode);
|
||||
if ((ellCount(&pnotifyPvt->waitList) != 0)) {
|
||||
restartCheck(precord->ppnr);
|
||||
} else if (pputNotifyPvt->state == putNotifyPutInProgress) {
|
||||
pputNotifyPvt->state = putNotifyUserCallbackRequested;
|
||||
}
|
||||
else if (pnotifyPvt->state == notifyProcessInProgress) {
|
||||
pnotifyPvt->state = notifyUserCallbackRequested;
|
||||
restartCheck(precord->ppnr);
|
||||
callbackRequest(&pputNotifyPvt->callback);
|
||||
} else if (pputNotifyPvt->state == putNotifyRestartInProgress) {
|
||||
pputNotifyPvt->state = putNotifyRestartCallbackRequested;
|
||||
callbackRequest(&pputNotifyPvt->callback);
|
||||
callbackRequest(&pnotifyPvt->callback);
|
||||
}
|
||||
else if(pnotifyPvt->state == notifyRestartInProgress) {
|
||||
pnotifyPvt->state = notifyRestartCallbackRequested;
|
||||
callbackRequest(&pnotifyPvt->callback);
|
||||
} else {
|
||||
cantProceed("dbNotifyCompletion illegal state");
|
||||
}
|
||||
@@ -434,59 +462,112 @@ void epicsShareAPI dbNotifyCompletion(dbCommon *precord)
|
||||
|
||||
void epicsShareAPI dbNotifyAdd(dbCommon *pfrom, dbCommon *pto)
|
||||
{
|
||||
putNotify *ppn = pfrom->ppn;
|
||||
putNotifyPvt *pputNotifyPvt;
|
||||
processNotify *ppn = pfrom->ppn;
|
||||
notifyPvt *pnotifyPvt;
|
||||
|
||||
if (pto->pact)
|
||||
return; /*if active it will not be processed*/
|
||||
epicsMutexMustLock(pnotifyGlobal->lock);
|
||||
if (!pto->ppnr) {/* make sure record has a putNotifyRecord*/
|
||||
pto->ppnr = dbCalloc(1,sizeof(putNotifyRecord));
|
||||
if (!pto->ppnr) {/* make sure record has a processNotifyRecord*/
|
||||
pto->ppnr = dbCalloc(1, sizeof(processNotifyRecord));
|
||||
pto->ppnr->precord = pto;
|
||||
ellInit(&pto->ppnr->restartList);
|
||||
}
|
||||
assert(ppn);
|
||||
pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
|
||||
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
|
||||
if (!pto->ppn &&
|
||||
(pputNotifyPvt->state == putNotifyPutInProgress) &&
|
||||
(pnotifyPvt->state == notifyProcessInProgress) &&
|
||||
(pto != dbChannelRecord(ppn->chan))) {
|
||||
putNotifyPvt *pputNotifyPvt;
|
||||
notifyPvt *pnotifyPvt;
|
||||
pto->ppn = pfrom->ppn;
|
||||
pputNotifyPvt = (putNotifyPvt *) pfrom->ppn->pputNotifyPvt;
|
||||
ellSafeAdd(&pputNotifyPvt->waitList,&pto->ppnr->waitNode);
|
||||
pnotifyPvt = (notifyPvt *) pfrom->ppn->pnotifyPvt;
|
||||
ellSafeAdd(&pnotifyPvt->waitList, &pto->ppnr->waitNode);
|
||||
}
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
}
|
||||
|
||||
typedef struct tpnInfo {
|
||||
epicsEventId callbackDone;
|
||||
putNotify *ppn;
|
||||
processNotify *ppn;
|
||||
char buffer[80];
|
||||
} tpnInfo;
|
||||
|
||||
static void dbtpnCallback(putNotify *ppn)
|
||||
static int putCallback(processNotify *ppn, notifyPutType type)
|
||||
{
|
||||
putNotifyStatus status = ppn->status;
|
||||
tpnInfo *ptpnInfo = (tpnInfo *) ppn->usrPvt;
|
||||
int status = 0;
|
||||
|
||||
if (ppn->status == notifyCanceled)
|
||||
return 0;
|
||||
ppn->status = notifyOK;
|
||||
switch (type) {
|
||||
case putDisabledType:
|
||||
ppn->status = notifyError;
|
||||
return 0;
|
||||
case putFieldType:
|
||||
status = dbChannelPutField(ppn->chan, DBR_STRING, ptpnInfo->buffer, 1);
|
||||
break;
|
||||
case putType:
|
||||
status = dbChannelPut(ppn->chan, DBR_STRING, ptpnInfo->buffer, 1);
|
||||
break;
|
||||
}
|
||||
if (status)
|
||||
ppn->status = notifyError;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void getCallback(processNotify *ppn,notifyGetType type)
|
||||
{
|
||||
tpnInfo *ptpnInfo = (tpnInfo *)ppn->usrPvt;
|
||||
int status = 0;
|
||||
long no_elements = 1;
|
||||
long options = 0;
|
||||
|
||||
if(ppn->status==notifyCanceled) {
|
||||
printf("dbtpn:getCallback notifyCanceled\n");
|
||||
return;
|
||||
}
|
||||
switch(type) {
|
||||
case getFieldType:
|
||||
status = dbChannelGetField(ppn->chan, DBR_STRING, ptpnInfo->buffer,
|
||||
&options, &no_elements, 0);
|
||||
break;
|
||||
case getType:
|
||||
status = dbChannelGet(ppn->chan, DBR_STRING, ptpnInfo->buffer,
|
||||
&options, &no_elements, 0);
|
||||
break;
|
||||
}
|
||||
if (status) {
|
||||
ppn->status = notifyError;
|
||||
printf("dbtpn:getCallback error\n");
|
||||
} else {
|
||||
printf("dbtpn:getCallback value %s\n", ptpnInfo->buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void doneCallback(processNotify *ppn)
|
||||
{
|
||||
notifyStatus status = ppn->status;
|
||||
tpnInfo *ptpnInfo = (tpnInfo *) ppn->usrPvt;
|
||||
const char *pname = dbChannelRecord(ppn->chan)->name;
|
||||
|
||||
if (status == 0)
|
||||
printf("dbtpnCallback: success record=%s\n", pname);
|
||||
else
|
||||
printf("%s dbtpnCallback putNotify.status %d\n",
|
||||
pname, (int) status);
|
||||
printf("%s dbtpnCallback processNotify.status %d\n",
|
||||
pname, (int) status);
|
||||
epicsEventSignal(ptpnInfo->callbackDone);
|
||||
}
|
||||
|
||||
static void tpnThread(void *pvt)
|
||||
{
|
||||
tpnInfo *ptpnInfo = (tpnInfo *) pvt;
|
||||
putNotify *ppn = (putNotify *) ptpnInfo->ppn;
|
||||
processNotify *ppn = (processNotify *) ptpnInfo->ppn;
|
||||
|
||||
dbPutNotify(ppn);
|
||||
dbProcessNotify(ppn);
|
||||
epicsEventWait(ptpnInfo->callbackDone);
|
||||
dbNotifyCancel(ppn);
|
||||
epicsEventDestroy(ptpnInfo->callbackDone);
|
||||
free(ppn->pbuffer);
|
||||
dbChannelDelete(ppn->chan);
|
||||
free(ppn);
|
||||
free(ptpnInfo);
|
||||
@@ -496,28 +577,30 @@ long epicsShareAPI dbtpn(char *pname, char *pvalue)
|
||||
{
|
||||
struct dbChannel *chan;
|
||||
tpnInfo *ptpnInfo;
|
||||
putNotify *ppn;
|
||||
char *pbuffer;
|
||||
processNotify *ppn=NULL;
|
||||
|
||||
pbuffer = epicsStrDup(pvalue);
|
||||
chan = dbChannelCreate(pname);
|
||||
if (!chan) {
|
||||
printf("dbtpn: No such channel");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ppn = dbCalloc(1, sizeof(putNotify));
|
||||
|
||||
ppn = dbCalloc(1, sizeof(processNotify));
|
||||
ppn->requestType = pvalue ? putProcessRequest : processGetRequest;
|
||||
ppn->chan = chan;
|
||||
ppn->pbuffer = pbuffer;
|
||||
ppn->nRequest = 1;
|
||||
ppn->dbrType = DBR_STRING;
|
||||
ppn->userCallback = dbtpnCallback;
|
||||
ppn->putCallback = putCallback;
|
||||
ppn->getCallback = getCallback;
|
||||
ppn->doneCallback = doneCallback;
|
||||
|
||||
ptpnInfo = dbCalloc(1, sizeof(tpnInfo));
|
||||
ptpnInfo->ppn = ppn;
|
||||
ptpnInfo->callbackDone = epicsEventCreate(epicsEventEmpty);
|
||||
strncpy(ptpnInfo->buffer, pvalue, 80);
|
||||
ptpnInfo->buffer[79] = 0;
|
||||
|
||||
ppn->usrPvt = ptpnInfo;
|
||||
epicsThreadCreate("dbtpn", epicsThreadPriorityHigh,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium), tpnThread, ptpnInfo);
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium), tpnThread, ptpnInfo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -525,11 +608,8 @@ int epicsShareAPI dbNotifyDump(void)
|
||||
{
|
||||
epicsMutexLockStatus lockStatus;
|
||||
dbRecordType *pdbRecordType;
|
||||
dbRecordNode *pdbRecordNode;
|
||||
dbCommon *precord;
|
||||
putNotify *ppn;
|
||||
putNotify *ppnRestart;
|
||||
putNotifyRecord *ppnrWait;
|
||||
processNotify *ppnRestart;
|
||||
processNotifyRecord *ppnr;
|
||||
int itry;
|
||||
|
||||
for (itry = 0; itry < 100; itry++) {
|
||||
@@ -538,39 +618,52 @@ int epicsShareAPI dbNotifyDump(void)
|
||||
break;
|
||||
epicsThreadSleep(.05);
|
||||
}
|
||||
for (pdbRecordType = (dbRecordType *) ellFirst(&pdbbase->recordTypeList); pdbRecordType; pdbRecordType
|
||||
= (dbRecordType *) ellNext(&pdbRecordType->node)) {
|
||||
for (pdbRecordNode = (dbRecordNode *) ellFirst(&pdbRecordType->recList); pdbRecordNode; pdbRecordNode
|
||||
= (dbRecordNode *) ellNext(&pdbRecordNode->node)) {
|
||||
putNotifyPvt *pputNotifyPvt;
|
||||
precord = pdbRecordNode->precord;
|
||||
|
||||
for (pdbRecordType = (dbRecordType *) ellFirst(&pdbbase->recordTypeList);
|
||||
pdbRecordType;
|
||||
pdbRecordType = (dbRecordType *) ellNext(&pdbRecordType->node)) {
|
||||
dbRecordNode *pdbRecordNode;
|
||||
|
||||
for (pdbRecordNode = (dbRecordNode *) ellFirst(&pdbRecordType->recList);
|
||||
pdbRecordNode;
|
||||
pdbRecordNode = (dbRecordNode *) ellNext(&pdbRecordNode->node)) {
|
||||
dbCommon *precord = pdbRecordNode->precord;
|
||||
processNotify *ppn;
|
||||
notifyPvt *pnotifyPvt;
|
||||
|
||||
if (!precord->name[0] || pdbRecordNode->flags & DBRN_FLAGS_ISALIAS)
|
||||
continue;
|
||||
if (!precord->ppn)
|
||||
continue;
|
||||
if (!precord->ppnr)
|
||||
ppn = precord->ppn;
|
||||
if (!ppn || !precord->ppnr)
|
||||
continue;
|
||||
if (dbChannelRecord(precord->ppn->chan) != precord)
|
||||
continue;
|
||||
ppn = precord->ppn;
|
||||
pputNotifyPvt = (putNotifyPvt *) ppn->pputNotifyPvt;
|
||||
printf("%s state %d ppn %p\n waitList\n", precord->name,
|
||||
pputNotifyPvt->state, (void*) ppn);
|
||||
ppnrWait = (putNotifyRecord *) ellFirst(&pputNotifyPvt->waitList);
|
||||
while (ppnrWait) {
|
||||
printf(" %s pact %d\n", ppnrWait->precord->name,
|
||||
ppnrWait->precord->pact);
|
||||
ppnrWait = (putNotifyRecord *) ellNext(&ppnrWait->waitNode.node);
|
||||
|
||||
pnotifyPvt = (notifyPvt *) ppn->pnotifyPvt;
|
||||
printf("%s state %d ppn %p\n waitList\n",
|
||||
precord->name, pnotifyPvt->state, (void*) ppn);
|
||||
ppnr = (processNotifyRecord *) ellFirst(&pnotifyPvt->waitList);
|
||||
while (ppnr) {
|
||||
printf(" %s pact %d\n",
|
||||
ppnr->precord->name, ppnr->precord->pact);
|
||||
ppnr = (processNotifyRecord *) ellNext(&ppnr->waitNode.node);
|
||||
}
|
||||
printf(" restartList\n");
|
||||
ppnRestart = (putNotify *) ellFirst(&precord->ppnr->restartList);
|
||||
while (ppnRestart) {
|
||||
printf(" %p\n", (void *) ppnRestart);
|
||||
ppnRestart = (putNotify *) ellNext(&ppnRestart->restartNode.node);
|
||||
ppnr = precord->ppnr;
|
||||
if (ppnr) {
|
||||
ppnRestart = (processNotify *)ellFirst(
|
||||
&precord->ppnr->restartList);
|
||||
if (ppnRestart)
|
||||
printf("%s restartList\n", precord->name);
|
||||
while (ppnRestart) {
|
||||
printf(" %s\n", dbChannelRecord(ppnRestart->chan)->name);
|
||||
ppnRestart = (processNotify *) ellNext(
|
||||
&ppnRestart->restartNode.node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lockStatus == epicsMutexLockOK)
|
||||
epicsMutexUnlock(pnotifyGlobal->lock);
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+102
-57
@@ -3,8 +3,7 @@
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* dbNotify.h */
|
||||
@@ -22,44 +21,61 @@
|
||||
#endif
|
||||
|
||||
struct dbCommon;
|
||||
struct putNotify;
|
||||
struct processNotify;
|
||||
|
||||
typedef struct ellCheckNode{
|
||||
ELLNODE node;
|
||||
int isOnList;
|
||||
}ellCheckNode;
|
||||
} ellCheckNode;
|
||||
|
||||
typedef enum {
|
||||
putNotifyOK,
|
||||
putNotifyCanceled,
|
||||
putNotifyError,
|
||||
putNotifyPutDisabled
|
||||
}putNotifyStatus;
|
||||
processRequest,
|
||||
putProcessRequest,
|
||||
processGetRequest,
|
||||
putProcessGetRequest
|
||||
} notifyRequestType;
|
||||
|
||||
typedef struct putNotify{
|
||||
ellCheckNode restartNode;
|
||||
/*The following members MUST be set by user*/
|
||||
void (*userCallback)(struct putNotify *);
|
||||
struct dbChannel *chan; /*dbChannel*/
|
||||
void *pbuffer; /*address of data*/
|
||||
long nRequest; /*number of elements to be written*/
|
||||
short dbrType; /*database request type*/
|
||||
void *usrPvt; /*for private use of user*/
|
||||
/*The following is status of request. Set by dbNotify */
|
||||
putNotifyStatus status;
|
||||
void *pputNotifyPvt; /*for private use of putNotify*/
|
||||
}putNotify;
|
||||
typedef enum {
|
||||
putDisabledType,
|
||||
putFieldType,
|
||||
putType
|
||||
} notifyPutType;
|
||||
|
||||
/* dbPutNotify and dbNotifyCancel are the routines called by user*/
|
||||
/* The user is normally channel access client or server */
|
||||
epicsShareFunc void epicsShareAPI dbPutNotify(putNotify *pputNotify);
|
||||
epicsShareFunc void epicsShareAPI dbNotifyCancel(putNotify *pputNotify);
|
||||
typedef enum {
|
||||
getFieldType,
|
||||
getType /* FIXME: Never used? */
|
||||
} notifyGetType;
|
||||
|
||||
/*dbPutNotifyMapType convenience function for old database access*/
|
||||
epicsShareFunc int epicsShareAPI dbPutNotifyMapType (putNotify *ppn, short oldtype);
|
||||
typedef enum {
|
||||
notifyOK,
|
||||
notifyCanceled,
|
||||
notifyError,
|
||||
notifyPutDisabled
|
||||
} notifyStatus;
|
||||
|
||||
/* dbPutNotifyInit called by iocInit */
|
||||
epicsShareFunc void epicsShareAPI dbPutNotifyInit(void);
|
||||
typedef struct processNotify {
|
||||
/* following fields are for private use by dbNotify implementation */
|
||||
ellCheckNode restartNode;
|
||||
void *pnotifyPvt;
|
||||
/* The following fields are set by dbNotify. */
|
||||
notifyStatus status;
|
||||
int wasProcessed; /* (0,1) => (no,yes) */
|
||||
/*The following members are set by user*/
|
||||
notifyRequestType requestType;
|
||||
struct dbChannel *chan; /*dbChannel*/
|
||||
int (*putCallback)(struct processNotify *,notifyPutType type);
|
||||
void (*getCallback)(struct processNotify *,notifyGetType type);
|
||||
void (*doneCallback)(struct processNotify *);
|
||||
void *usrPvt; /*for private use of user*/
|
||||
} processNotify;
|
||||
|
||||
|
||||
/* dbProcessNotify and dbNotifyCancel are called by user*/
|
||||
epicsShareFunc void epicsShareAPI dbProcessNotify(processNotify *pprocessNotify);
|
||||
epicsShareFunc void epicsShareAPI dbNotifyCancel(processNotify *pprocessNotify);
|
||||
|
||||
/* dbProcessNotifyInit called by iocInit */
|
||||
epicsShareFunc void epicsShareAPI dbProcessNotifyInit(void);
|
||||
|
||||
/*dbNotifyAdd called by dbScanPassive and dbScanLink*/
|
||||
epicsShareFunc void epicsShareAPI dbNotifyAdd(
|
||||
@@ -67,29 +83,60 @@ epicsShareFunc void epicsShareAPI dbNotifyAdd(
|
||||
/*dbNotifyCompletion called by recGblFwdLink or dbAccess*/
|
||||
epicsShareFunc void epicsShareAPI dbNotifyCompletion(struct dbCommon *precord);
|
||||
|
||||
/* dbtpn is test routine for put notify */
|
||||
/* db_put_process defined here since it requires dbNotify.
|
||||
* src_type is the old DBR type
|
||||
* This is called by a dbNotify putCallback that uses oldDbr types
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI db_put_process(
|
||||
processNotify *processNotify,notifyPutType type,
|
||||
int src_type,const void *psrc, int no_elements);
|
||||
|
||||
/* dbtpn is test routine for dbNotify putProcessRequest */
|
||||
epicsShareFunc long epicsShareAPI dbtpn(char *recordname,char *value);
|
||||
|
||||
/* dbNotifyDump is an INVASIVE debug utility. Don't use this needlessly*/
|
||||
epicsShareFunc int epicsShareAPI dbNotifyDump(void);
|
||||
|
||||
/* This module provides code to handle put notify. If a put causes a record to
|
||||
* be processed, then a user supplied callback is called when that record
|
||||
* and all records processed because of that record complete processing.
|
||||
* For asynchronous records completion means completion of the asyn phase.
|
||||
/* This module provides code to handle process notify.
|
||||
* client code semantics are:
|
||||
* 1) The client code allocates storage for a processNotify structure.
|
||||
* This structure can be used for multiple calls to dbProcessNotify.
|
||||
* The client is responsible for setting the following fields :
|
||||
* requestType - The type of request.
|
||||
* chan - This is typically set via a call to dbChannelCreate.
|
||||
* putCallback - If requestType is putProcessRequest or putProcessGetRequest
|
||||
* getCallback - If request is processGetRequest or putProcessGetRequest
|
||||
* doneCallback - Must be set
|
||||
* usrPvt - For exclusive use of client. dbNotify does not access this field
|
||||
* 2) The client calls dbProcessNotify.
|
||||
* 3) putCallback is called after dbNotify has claimed the record instance
|
||||
* but before a potential process is requested.
|
||||
* The putCallback MUST issue the correct put request
|
||||
* specified by notifyPutType
|
||||
* 4) getCallback is called after a possible process is complete
|
||||
* (including asynchronous completion) but before dbNotify has
|
||||
* released the record.
|
||||
* The getCallback MUST issue the correct get request
|
||||
* specified by notifyGetType
|
||||
* 5) doneCallback is called when dbNotify has released the record.
|
||||
* The client can issue a new dbProcessNotify request from
|
||||
* doneCallback or anytime after doneCallback returns.
|
||||
* 6) The client can call dbNotifyCancel at any time.
|
||||
* If a dbProcessNotify is active, dbNotifyCancel will not return until
|
||||
* the dbNotifyRequest is actually canceled. The client must be prepared
|
||||
* for a callback to be called while dbNotifyCancel is active.
|
||||
*
|
||||
* User code calls putNotifyInit, putNotifyCleanup,
|
||||
* dbPutNotify, and dbNotifyCancel.
|
||||
* dbProcessNotify handles the semantics of record locking and deciding
|
||||
* if a process request is issued and also calls the client callbacks.
|
||||
*
|
||||
* The use must allocate storage for "struct putNotify"
|
||||
* The user MUST set pputNotifyPvt=0 before the first call to dbPutNotify
|
||||
* and should never modify it again.
|
||||
* A process request is issued if any of the following is true.
|
||||
* 1) The requester has issued a processs request and record is passive.
|
||||
* 2) The requester is doing a put, the record is passive, and either
|
||||
* a) The field description is process passive.
|
||||
* b) The field is PROC.
|
||||
* 3) The requester has requested processGet and the record is passive.
|
||||
*
|
||||
* After dbPutNotify is called it may not called for the same putNotify
|
||||
* until the putCallback is complete. The use can call dbNotifyCancel
|
||||
* to cancel the operation.
|
||||
*
|
||||
* The user callback is called when the operation is completed.
|
||||
* iocInit calls processNotifyInit.
|
||||
*
|
||||
* The other global routines (dbNotifyAdd and dbNotifyCompletion) are called by:
|
||||
*
|
||||
@@ -101,22 +148,20 @@ epicsShareFunc int epicsShareAPI dbNotifyDump(void);
|
||||
* Unless pact is already true.
|
||||
* recGbl
|
||||
* recGblFwdLink calls dbNotifyCompletion
|
||||
*/
|
||||
|
||||
/* Two fields in dbCommon are used for put notify.
|
||||
* ppn pointer to putNotify
|
||||
* If a record is part of a put notify group,
|
||||
* This field is the address of the associated putNotify.
|
||||
* As soon as a record completes processing the field is set NULL
|
||||
* ppnr pointer to putNotifyRecord
|
||||
* Address of a putNotifyRecord for 1) list node for records
|
||||
* put notify is waiting to complete, and 2) a list of records
|
||||
* to restart.
|
||||
*
|
||||
* See the Application Developer's Guide for implementation rules
|
||||
* Two fields in dbCommon are used for put notify.
|
||||
* ppn pointer to processNotify
|
||||
* If a record is part of a put notify group,
|
||||
* This field is the address of the associated processNotify.
|
||||
* As soon as a record completes processing the field is set NULL
|
||||
* ppnr pointer to processNotifyRecord, which is a private structure
|
||||
* owned by dbNotify.
|
||||
* dbNotify is reponsible for this structure.
|
||||
*
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*INCdbNotifyh*/
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* Copyright (c) 2012 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 Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
@@ -52,7 +51,7 @@ dbPutNotifyBlocker::dbPutNotifyBlocker ( epicsMutex & mutexIn ) :
|
||||
{
|
||||
memset ( & this->pn, '\0', sizeof ( this->pn ) );
|
||||
memset ( & this->dbrScalarValue, '\0', sizeof ( this->dbrScalarValue ) );
|
||||
this->pn.pbuffer = & this->dbrScalarValue;
|
||||
this->pbuffer = & this->dbrScalarValue;
|
||||
}
|
||||
|
||||
dbPutNotifyBlocker::~dbPutNotifyBlocker ()
|
||||
@@ -64,7 +63,7 @@ void dbPutNotifyBlocker::destructor ( epicsGuard < epicsMutex > & guard )
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
this->cancel ( guard );
|
||||
if ( this->maxValueSize > sizeof ( this->dbrScalarValue ) ) {
|
||||
char * pBuf = static_cast < char * > ( this->pn.pbuffer );
|
||||
char * pBuf = static_cast < char * > ( this->pbuffer );
|
||||
delete [] pBuf;
|
||||
}
|
||||
this->~dbPutNotifyBlocker ();
|
||||
@@ -88,17 +87,29 @@ void dbPutNotifyBlocker::expandValueBuf (
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
if ( this->maxValueSize < newSize ) {
|
||||
if ( this->maxValueSize > sizeof ( this->dbrScalarValue ) ) {
|
||||
char * pBuf = static_cast < char * > ( this->pn.pbuffer );
|
||||
char * pBuf = static_cast < char * > ( this->pbuffer );
|
||||
delete [] pBuf;
|
||||
this->maxValueSize = sizeof ( this->dbrScalarValue );
|
||||
this->pn.pbuffer = & this->dbrScalarValue;
|
||||
this->pbuffer = & this->dbrScalarValue;
|
||||
}
|
||||
this->pn.pbuffer = new char [newSize];
|
||||
this->pbuffer = new char [newSize];
|
||||
this->maxValueSize = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void putNotifyCompletion ( putNotify *ppn )
|
||||
extern "C" int putNotifyPut ( processNotify *ppn, notifyPutType type )
|
||||
{
|
||||
if(ppn->status==notifyCanceled) return 0;
|
||||
/*
|
||||
* No locking in this method because only a dbNotifyCancel could interrupt
|
||||
* and it does not return until cancel is done.
|
||||
*/
|
||||
dbPutNotifyBlocker * pBlocker = static_cast < dbPutNotifyBlocker * > ( ppn->usrPvt );
|
||||
return db_put_process(ppn,type,
|
||||
pBlocker->dbrType,pBlocker->pbuffer,pBlocker->nRequest);
|
||||
}
|
||||
|
||||
extern "C" void putNotifyCompletion ( processNotify *ppn )
|
||||
{
|
||||
dbPutNotifyBlocker * const pBlocker =
|
||||
static_cast < dbPutNotifyBlocker * > ( ppn->usrPvt );
|
||||
@@ -112,11 +123,11 @@ extern "C" void putNotifyCompletion ( putNotify *ppn )
|
||||
// unavoidable because its possible that the use callback
|
||||
// might destroy this object.
|
||||
pBlocker->block.signal ();
|
||||
if ( pBlocker->pn.status != putNotifyOK ) {
|
||||
if ( pBlocker->pn.status != notifyOK ) {
|
||||
pNtfy->exception (
|
||||
guard, ECA_PUTFAIL, "put notify unsuccessful",
|
||||
static_cast < unsigned > (pBlocker->pn.dbrType),
|
||||
static_cast < unsigned > (pBlocker->pn.nRequest) );
|
||||
static_cast < unsigned > (pBlocker->dbrType),
|
||||
static_cast < unsigned > (pBlocker->nRequest) );
|
||||
}
|
||||
else {
|
||||
pNtfy->completion ( guard );
|
||||
@@ -163,25 +174,21 @@ void dbPutNotifyBlocker::initiatePutNotify (
|
||||
throw cacChannel::badType();
|
||||
}
|
||||
|
||||
int status = dbPutNotifyMapType (
|
||||
&this->pn, static_cast <short> ( type ) );
|
||||
if ( status ) {
|
||||
this->pNotify = 0;
|
||||
throw cacChannel::badType();
|
||||
}
|
||||
|
||||
this->pn.nRequest = static_cast < unsigned > ( count );
|
||||
this->dbrType = type;
|
||||
this->nRequest = static_cast < unsigned > ( count );
|
||||
this->pn.requestType = putProcessRequest;
|
||||
this->pn.chan = dbch;
|
||||
this->pn.userCallback = putNotifyCompletion;
|
||||
this->pn.putCallback = putNotifyPut;
|
||||
this->pn.doneCallback = putNotifyCompletion;
|
||||
this->pn.usrPvt = this;
|
||||
|
||||
unsigned long size = dbr_size_n ( type, count );
|
||||
this->expandValueBuf ( guard, size );
|
||||
memcpy ( this->pn.pbuffer, pValue, size );
|
||||
memcpy ( this->pbuffer, pValue, size );
|
||||
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > autoRelease ( guard );
|
||||
::dbPutNotify ( &this->pn );
|
||||
::dbProcessNotify ( &this->pn );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
epicsPlacementDeleteOperator (( void *,
|
||||
tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & ))
|
||||
private:
|
||||
putNotify pn;
|
||||
processNotify pn;
|
||||
//
|
||||
// Include a union of all scalar types
|
||||
// including fixed length strings so
|
||||
@@ -75,10 +75,16 @@ private:
|
||||
epicsMutex & mutex;
|
||||
cacWriteNotify * pNotify;
|
||||
unsigned long maxValueSize;
|
||||
// arguments for db_put_field
|
||||
void *pbuffer;
|
||||
long nRequest;
|
||||
short dbrType;
|
||||
// end arguments for db_put_field
|
||||
dbSubscriptionIO * isSubscription ();
|
||||
void expandValueBuf (
|
||||
epicsGuard < epicsMutex > &, unsigned long newSize );
|
||||
friend void putNotifyCompletion ( putNotify * ppn );
|
||||
friend void putNotifyCompletion ( processNotify * ppn );
|
||||
friend int putNotifyPut ( processNotify *ppn, notifyPutType type );
|
||||
dbPutNotifyBlocker ( const dbPutNotifyBlocker & );
|
||||
dbPutNotifyBlocker & operator = ( const dbPutNotifyBlocker & );
|
||||
virtual ~dbPutNotifyBlocker ();
|
||||
|
||||
+45
-22
@@ -973,39 +973,62 @@ int dbChannel_put(struct dbChannel *chan, int src_type,
|
||||
}
|
||||
|
||||
|
||||
epicsShareFunc int epicsShareAPI dbPutNotifyMapType (putNotify *ppn, short oldtype)
|
||||
static int mapOldType (short oldtype)
|
||||
{
|
||||
switch(oldtype) {
|
||||
case(oldDBR_STRING):
|
||||
ppn->dbrType = DBR_STRING;
|
||||
int dbrType = -1;
|
||||
|
||||
switch (oldtype) {
|
||||
case oldDBR_STRING:
|
||||
dbrType = DBR_STRING;
|
||||
break;
|
||||
/* case(oldDBR_INT): */
|
||||
case(oldDBR_SHORT):
|
||||
ppn->dbrType = DBR_SHORT;
|
||||
/* case oldDBR_INT: */
|
||||
case oldDBR_SHORT:
|
||||
dbrType = DBR_SHORT;
|
||||
break;
|
||||
case(oldDBR_FLOAT):
|
||||
ppn->dbrType = DBR_FLOAT;
|
||||
case oldDBR_FLOAT:
|
||||
dbrType = DBR_FLOAT;
|
||||
break;
|
||||
case(oldDBR_ENUM):
|
||||
ppn->dbrType = DBR_ENUM;
|
||||
case oldDBR_ENUM:
|
||||
dbrType = DBR_ENUM;
|
||||
break;
|
||||
case(oldDBR_CHAR):
|
||||
ppn->dbrType = DBR_UCHAR;
|
||||
case oldDBR_CHAR:
|
||||
dbrType = DBR_UCHAR;
|
||||
break;
|
||||
case(oldDBR_LONG):
|
||||
ppn->dbrType = DBR_LONG;
|
||||
case oldDBR_LONG:
|
||||
dbrType = DBR_LONG;
|
||||
break;
|
||||
case(oldDBR_DOUBLE):
|
||||
ppn->dbrType = DBR_DOUBLE;
|
||||
case oldDBR_DOUBLE:
|
||||
dbrType = DBR_DOUBLE;
|
||||
break;
|
||||
case(oldDBR_PUT_ACKT):
|
||||
ppn->dbrType = DBR_PUT_ACKT;
|
||||
case oldDBR_PUT_ACKT:
|
||||
dbrType = DBR_PUT_ACKT;
|
||||
break;
|
||||
case(oldDBR_PUT_ACKS):
|
||||
ppn->dbrType = DBR_PUT_ACKS;
|
||||
case oldDBR_PUT_ACKS:
|
||||
dbrType = DBR_PUT_ACKS;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
return dbrType;
|
||||
}
|
||||
|
||||
int epicsShareAPI db_put_process(processNotify *ppn, notifyPutType type,
|
||||
int src_type, const void *psrc, int no_elements)
|
||||
{
|
||||
int status = 0;
|
||||
int dbrType = mapOldType(src_type);
|
||||
switch(type) {
|
||||
case putDisabledType:
|
||||
ppn->status = notifyError;
|
||||
return 0;
|
||||
case putFieldType:
|
||||
status = dbChannelPutField(ppn->chan, dbrType, psrc, no_elements);
|
||||
break;
|
||||
case putType:
|
||||
status = dbChannelPut(ppn->chan, dbrType, psrc, no_elements);
|
||||
break;
|
||||
}
|
||||
if (status)
|
||||
ppn->status = notifyError;
|
||||
return 1;
|
||||
}
|
||||
|
||||
+28
-25
@@ -1,10 +1,9 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* Copyright (c) 2012 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 Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
@@ -180,33 +179,39 @@ int epicsShareAPI pft(char *pname, char *pvalue)
|
||||
|
||||
typedef struct tpnInfo {
|
||||
epicsEventId callbackDone;
|
||||
putNotify *ppn;
|
||||
struct dbChannel *chan;
|
||||
processNotify *ppn;
|
||||
char buffer[80];
|
||||
} tpnInfo;
|
||||
|
||||
static void tpnCallback(putNotify *ppn)
|
||||
|
||||
static int putCallback(processNotify *ppn,notifyPutType type) {
|
||||
tpnInfo *ptpnInfo = (tpnInfo *)ppn->usrPvt;
|
||||
|
||||
return db_put_process(ppn, type, DBR_STRING, ptpnInfo->buffer, 1);
|
||||
}
|
||||
|
||||
static void doneCallback(processNotify *ppn)
|
||||
{
|
||||
tpnInfo *ptpnInfo = (tpnInfo *) ppn->usrPvt;
|
||||
putNotifyStatus status = ppn->status;
|
||||
notifyStatus status = ppn->status;
|
||||
const char *pname = dbChannelRecord(ppn->chan)->name;
|
||||
|
||||
if (status == 0)
|
||||
printf("tpnCallback: success record=%s\n", pname);
|
||||
printf("tpnCallback '%s': Success\n", pname);
|
||||
else
|
||||
printf("%s tpnCallback status = %d\n", pname, status);
|
||||
printf("tpnCallback '%s': Notify status %d\n", pname, (int)status);
|
||||
epicsEventSignal(ptpnInfo->callbackDone);
|
||||
}
|
||||
|
||||
static void tpnThread(void *pvt)
|
||||
{
|
||||
tpnInfo *ptpnInfo = (tpnInfo *) pvt;
|
||||
putNotify *ppn = (putNotify *) ptpnInfo->ppn;
|
||||
processNotify *ppn = (processNotify *) ptpnInfo->ppn;
|
||||
|
||||
dbPutNotify(ppn);
|
||||
dbProcessNotify(ppn);
|
||||
epicsEventWait(ptpnInfo->callbackDone);
|
||||
dbNotifyCancel(ppn);
|
||||
epicsEventDestroy(ptpnInfo->callbackDone);
|
||||
free(ppn->pbuffer);
|
||||
dbChannelDelete(ppn->chan);
|
||||
free(ppn);
|
||||
free(ptpnInfo);
|
||||
@@ -216,8 +221,7 @@ int epicsShareAPI tpn(char *pname, char *pvalue)
|
||||
{
|
||||
struct dbChannel *chan;
|
||||
tpnInfo *ptpnInfo;
|
||||
putNotify *ppn;
|
||||
char *pbuffer;
|
||||
processNotify *ppn = NULL;
|
||||
|
||||
chan = dbChannel_create(pname);
|
||||
if (!chan) {
|
||||
@@ -225,21 +229,16 @@ int epicsShareAPI tpn(char *pname, char *pvalue)
|
||||
return 1;
|
||||
}
|
||||
|
||||
pbuffer = epicsStrDup(pvalue);
|
||||
ppn = calloc(1, sizeof(putNotify));
|
||||
ppn = calloc(1, sizeof(processNotify));
|
||||
if (!ppn) {
|
||||
printf("calloc failed\n");
|
||||
return -1;
|
||||
}
|
||||
ppn->requestType = putProcessRequest;
|
||||
ppn->chan = chan;
|
||||
ppn->pbuffer = pbuffer;
|
||||
ppn->nRequest = 1;
|
||||
if (dbPutNotifyMapType(ppn, DBR_STRING)) {
|
||||
printf("dbPutNotifyMapType failed\n");
|
||||
printf("calloc failed\n");
|
||||
return -1;
|
||||
}
|
||||
ppn->userCallback = tpnCallback;
|
||||
ppn->putCallback = putCallback;
|
||||
ppn->doneCallback = doneCallback;
|
||||
|
||||
ptpnInfo = calloc(1, sizeof(tpnInfo));
|
||||
if (!ptpnInfo) {
|
||||
printf("calloc failed\n");
|
||||
@@ -247,8 +246,12 @@ int epicsShareAPI tpn(char *pname, char *pvalue)
|
||||
}
|
||||
ptpnInfo->ppn = ppn;
|
||||
ptpnInfo->callbackDone = epicsEventCreate(epicsEventEmpty);
|
||||
strncpy(ptpnInfo->buffer, pvalue, 80);
|
||||
ptpnInfo->buffer[79] = 0;
|
||||
|
||||
ppn->usrPvt = ptpnInfo;
|
||||
epicsThreadCreate("tpn", epicsThreadPriorityHigh,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium), tpnThread, ptpnInfo);
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium), tpnThread, ptpnInfo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ epicsShareDef maplinkType pamaplinkType[LINK_NTYPES] = {
|
||||
{"GPIB_IO",GPIB_IO},
|
||||
{"BITBUS_IO",BITBUS_IO},
|
||||
{"MACRO_LINK",MACRO_LINK},
|
||||
{"PN_LINK",PN_LINK},
|
||||
{"DB_LINK",DB_LINK},
|
||||
{"CA_LINK",CA_LINK},
|
||||
{"INST_IO",INST_IO},
|
||||
@@ -290,7 +291,8 @@ static long setLinkType(DBENTRY *pdbentry)
|
||||
}
|
||||
|
||||
type = plink->type;
|
||||
if ((type == CONSTANT || type == PV_LINK || type == DB_LINK || type == CA_LINK) &&
|
||||
if ((type == CONSTANT || type == PV_LINK ||
|
||||
type == PN_LINK || type == DB_LINK || type == CA_LINK) &&
|
||||
(link_type == CONSTANT || link_type == PV_LINK)) goto done;
|
||||
|
||||
dbFreeLinkContents(plink);
|
||||
@@ -2022,6 +2024,14 @@ char * epicsShareAPI dbGetString(DBENTRY *pdbentry)
|
||||
strcpy(message,"");
|
||||
}
|
||||
break;
|
||||
case PN_LINK:
|
||||
if(plink->value.pv_link.pvname)
|
||||
strcpy(message,plink->value.pv_link.pvname);
|
||||
else
|
||||
strcpy(message,"");
|
||||
strcat(message," ");
|
||||
strcat(message,msstring[plink->value.pv_link.pvlMask&pvlOptMsMode]);
|
||||
break;
|
||||
case PV_LINK:
|
||||
case CA_LINK:
|
||||
case DB_LINK: {
|
||||
@@ -3709,6 +3719,7 @@ int epicsShareAPI dbGetLinkType(DBENTRY *pdbentry)
|
||||
case CONSTANT:
|
||||
return(DCT_LINK_CONSTANT);
|
||||
case PV_LINK:
|
||||
case PN_LINK:
|
||||
case DB_LINK:
|
||||
case CA_LINK:
|
||||
return(DCT_LINK_PV);
|
||||
|
||||
@@ -32,17 +32,19 @@ extern "C" {
|
||||
#define GPIB_IO 5
|
||||
#define BITBUS_IO 6
|
||||
#define MACRO_LINK 7
|
||||
|
||||
#define PN_LINK 9
|
||||
#define DB_LINK 10
|
||||
#define CA_LINK 11
|
||||
#define INST_IO 12 /* instrument */
|
||||
#define BBGPIB_IO 13 /* bitbus -> gpib */
|
||||
#define RF_IO 14
|
||||
#define VXI_IO 15
|
||||
#define LINK_NTYPES 14
|
||||
typedef struct maplinkType{
|
||||
#define LINK_NTYPES 15
|
||||
typedef struct maplinkType {
|
||||
char *strvalue;
|
||||
int value;
|
||||
}maplinkType;
|
||||
} maplinkType;
|
||||
|
||||
epicsShareExtern maplinkType pamaplinkType[];
|
||||
|
||||
|
||||
+13
-9
@@ -140,7 +140,7 @@ int iocBuild(void)
|
||||
errlogPrintf("iocBuild: asInit Failed.\n");
|
||||
return -1;
|
||||
}
|
||||
dbPutNotifyInit();
|
||||
dbProcessNotifyInit();
|
||||
epicsThreadSleep(.5);
|
||||
initHookAnnounce(initHookAfterScanInit);
|
||||
|
||||
@@ -428,7 +428,6 @@ static void doResolveLinks(dbRecordType *pdbRecordType, dbCommon *precord,
|
||||
{
|
||||
dbFldDes **papFldDes = pdbRecordType->papFldDes;
|
||||
short *link_ind = pdbRecordType->link_ind;
|
||||
devSup *pdevSup;
|
||||
int j;
|
||||
|
||||
/* For all the links in the record type... */
|
||||
@@ -436,16 +435,21 @@ static void doResolveLinks(dbRecordType *pdbRecordType, dbCommon *precord,
|
||||
dbFldDes *pdbFldDes = papFldDes[link_ind[j]];
|
||||
DBLINK *plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
|
||||
|
||||
if (ellCount(&precord->rdes->devList) > 0 &&
|
||||
(strcmp(pdbFldDes->name, "INP") == 0 || strcmp(pdbFldDes->name, "OUT") == 0)) {
|
||||
devSup *pdevSup = dbDTYPtoDevSup(pdbRecordType, precord->dtyp);
|
||||
|
||||
if (pdevSup) {
|
||||
struct dsxt *pdsxt = pdevSup->pdsxt;
|
||||
if (pdsxt && pdsxt->add_record) {
|
||||
pdsxt->add_record(precord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (plink->type == PV_LINK)
|
||||
dbInitLink(precord, plink, pdbFldDes->field_type);
|
||||
}
|
||||
pdevSup = dbDTYPtoDevSup(pdbRecordType, precord->dtyp);
|
||||
if (pdevSup) {
|
||||
struct dsxt *pdsxt = pdevSup->pdsxt;
|
||||
if (pdsxt && pdsxt->add_record) {
|
||||
pdsxt->add_record(precord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void doInitRecord1(dbRecordType *pdbRecordType, dbCommon *precord,
|
||||
|
||||
+51
-27
@@ -61,7 +61,7 @@ logBadIdWithFileAndLineno(CLIENT, MP, PPL, __FILE__, __LINE__)
|
||||
*/
|
||||
typedef struct rsrv_put_notify {
|
||||
ELLNODE node;
|
||||
putNotify dbPutNotify;
|
||||
processNotify dbPutNotify;
|
||||
caHdrLargeArray msg;
|
||||
/*
|
||||
* Include a union of all scalar types
|
||||
@@ -81,8 +81,13 @@ typedef struct rsrv_put_notify {
|
||||
dbr_long_t longval;
|
||||
dbr_double_t doubleval;
|
||||
} dbrScalarValue;
|
||||
/* arguments for db_put_field */
|
||||
void *pbuffer;
|
||||
long nRequest;
|
||||
short dbrType;
|
||||
/* end arguments for db_put_field */
|
||||
void * asWritePvt;
|
||||
unsigned valueSize; /* size of block pointed to by dbPutNotify */
|
||||
unsigned valueSize; /* size of block pointed to by pbuffer */
|
||||
char busy; /* put notify in progress */
|
||||
char onExtraLaborQueue;
|
||||
} RSRVPUTNOTIFY;
|
||||
@@ -1427,11 +1432,33 @@ static int claim_ciu_action ( caHdrLargeArray *mp,
|
||||
}
|
||||
|
||||
/*
|
||||
* write_notify_call_back()
|
||||
*
|
||||
* (called by the db call back thread)
|
||||
*/
|
||||
static void write_notify_call_back(putNotify *ppn)
|
||||
* write_notify_put_callback()
|
||||
*
|
||||
* (called by the db call back thread)
|
||||
*/
|
||||
LOCAL int write_notify_put_callback(processNotify *ppn,notifyPutType type)
|
||||
{
|
||||
struct channel_in_use * pciu = (struct channel_in_use *) ppn->usrPvt;
|
||||
struct rsrv_put_notify *pNotify;
|
||||
|
||||
if(ppn->status==notifyCanceled) return 0;
|
||||
/*
|
||||
* No locking in this method because only a dbNotifyCancel could interrupt
|
||||
* and it does not return until cancel is done.
|
||||
*/
|
||||
assert(pciu);
|
||||
assert(pciu->pPutNotify);
|
||||
pNotify = pciu->pPutNotify;
|
||||
return db_put_process(ppn,type,
|
||||
pNotify->dbrType,pNotify->pbuffer,pNotify->nRequest);
|
||||
}
|
||||
|
||||
/*
|
||||
* write_notify_done_callback()
|
||||
*
|
||||
* (called by the db call back thread)
|
||||
*/
|
||||
LOCAL void write_notify_done_callback(processNotify *ppn)
|
||||
{
|
||||
struct channel_in_use * pciu = (struct channel_in_use *) ppn->usrPvt;
|
||||
struct client * pClient;
|
||||
@@ -1497,7 +1524,7 @@ static void write_notify_reply ( struct client * pClient )
|
||||
* Map from DB status to CA status
|
||||
*
|
||||
*/
|
||||
if ( ppnb->dbPutNotify.status != putNotifyOK ) {
|
||||
if ( ppnb->dbPutNotify.status != notifyOK ) {
|
||||
status = ECA_PUTFAIL;
|
||||
}
|
||||
else{
|
||||
@@ -1630,14 +1657,16 @@ static struct rsrv_put_notify *
|
||||
pNotify = (RSRVPUTNOTIFY *)
|
||||
freeListCalloc ( rsrvPutNotifyFreeList );
|
||||
if ( pNotify ) {
|
||||
pNotify->dbPutNotify.pbuffer =
|
||||
&pNotify->dbrScalarValue;
|
||||
pNotify->pbuffer = &pNotify->dbrScalarValue;
|
||||
pNotify->valueSize =
|
||||
sizeof (pNotify->dbrScalarValue);
|
||||
pNotify->dbPutNotify.usrPvt = pciu;
|
||||
pNotify->dbPutNotify.chan = pciu->dbch;
|
||||
pNotify->dbPutNotify.userCallback =
|
||||
write_notify_call_back;
|
||||
pNotify->dbPutNotify.putCallback =
|
||||
write_notify_put_callback;
|
||||
pNotify->dbPutNotify.doneCallback =
|
||||
write_notify_done_callback;
|
||||
pNotify->dbPutNotify.requestType = putProcessRequest;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1659,10 +1688,10 @@ static int rsrvExpandPutNotify (
|
||||
*/
|
||||
if ( pNotify->valueSize >
|
||||
sizeof (pNotify->dbrScalarValue) ) {
|
||||
free ( pNotify->dbPutNotify.pbuffer );
|
||||
free ( pNotify->pbuffer );
|
||||
}
|
||||
pNotify->dbPutNotify.pbuffer = casCalloc(1,sizeNeeded);
|
||||
if ( pNotify->dbPutNotify.pbuffer ) {
|
||||
pNotify->pbuffer = casCalloc(1,sizeNeeded);
|
||||
if ( pNotify->pbuffer ) {
|
||||
pNotify->valueSize = sizeNeeded;
|
||||
booleanStatus = TRUE;
|
||||
}
|
||||
@@ -1670,7 +1699,7 @@ static int rsrvExpandPutNotify (
|
||||
/*
|
||||
* revert back to the embedded union
|
||||
*/
|
||||
pNotify->dbPutNotify.pbuffer =
|
||||
pNotify->pbuffer =
|
||||
&pNotify->dbrScalarValue;
|
||||
pNotify->valueSize =
|
||||
sizeof (pNotify->dbrScalarValue);
|
||||
@@ -1731,7 +1760,7 @@ void rsrvFreePutNotify ( client *pClient,
|
||||
|
||||
if ( pNotify->valueSize >
|
||||
sizeof(pNotify->dbrScalarValue) ) {
|
||||
free ( pNotify->dbPutNotify.pbuffer );
|
||||
free ( pNotify->pbuffer );
|
||||
}
|
||||
freeListFree ( rsrvPutNotifyFreeList, pNotify );
|
||||
}
|
||||
@@ -1805,7 +1834,7 @@ static int write_notify_action ( caHdrLargeArray *mp, void *pPayload,
|
||||
|
||||
if ( busyTmp ) {
|
||||
log_header("put call back time out", client,
|
||||
&pciu->pPutNotify->msg, pciu->pPutNotify->dbPutNotify.pbuffer, 0);
|
||||
&pciu->pPutNotify->msg, pciu->pPutNotify->pbuffer, 0);
|
||||
asTrapWriteAfter ( asWritePvtTmp );
|
||||
putNotifyErrorReply (client, &pciu->pPutNotify->msg, ECA_PUTCBINPROG);
|
||||
}
|
||||
@@ -1838,10 +1867,10 @@ static int write_notify_action ( caHdrLargeArray *mp, void *pPayload,
|
||||
pciu->pPutNotify->busy = TRUE;
|
||||
pciu->pPutNotify->onExtraLaborQueue = FALSE;
|
||||
pciu->pPutNotify->msg = *mp;
|
||||
pciu->pPutNotify->dbPutNotify.nRequest = mp->m_count;
|
||||
pciu->pPutNotify->nRequest = mp->m_count;
|
||||
|
||||
status = caNetConvert (
|
||||
mp->m_dataType, pPayload, pciu->pPutNotify->dbPutNotify.pbuffer,
|
||||
mp->m_dataType, pPayload, pciu->pPutNotify->pbuffer,
|
||||
FALSE /* net -> host format */, mp->m_count );
|
||||
if ( status != ECA_NORMAL ) {
|
||||
log_header ("invalid data type", client, mp, pPayload, 0);
|
||||
@@ -1849,12 +1878,7 @@ static int write_notify_action ( caHdrLargeArray *mp, void *pPayload,
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
|
||||
status = dbPutNotifyMapType(&pciu->pPutNotify->dbPutNotify, mp->m_dataType);
|
||||
if(status){
|
||||
putNotifyErrorReply (client, mp, ECA_PUTFAIL);
|
||||
pciu->pPutNotify->busy = FALSE;
|
||||
return RSRV_OK;
|
||||
}
|
||||
pciu->pPutNotify->dbrType = mp->m_dataType;
|
||||
|
||||
pciu->pPutNotify->asWritePvt = asTrapWriteBefore (
|
||||
pciu->asClientPVT,
|
||||
@@ -1862,7 +1886,7 @@ static int write_notify_action ( caHdrLargeArray *mp, void *pPayload,
|
||||
pciu->client->pHostName ? pciu->client->pHostName : "",
|
||||
pciu->dbch );
|
||||
|
||||
dbPutNotify(&pciu->pPutNotify->dbPutNotify);
|
||||
dbProcessNotify(&pciu->pPutNotify->dbPutNotify);
|
||||
|
||||
return RSRV_OK;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,13 @@ dbRecStd_SRCS += devSoSoft.c
|
||||
dbRecStd_SRCS += devWfSoft.c
|
||||
dbRecStd_SRCS += devGeneralTime.c
|
||||
|
||||
dbRecStd_SRCS += devAiSoftCallback.c
|
||||
dbRecStd_SRCS += devBiSoftCallback.c
|
||||
dbRecStd_SRCS += devLiSoftCallback.c
|
||||
dbRecStd_SRCS += devMbbiDirectSoftCallback.c
|
||||
dbRecStd_SRCS += devMbbiSoftCallback.c
|
||||
dbRecStd_SRCS += devSiSoftCallback.c
|
||||
|
||||
dbRecStd_SRCS += devAoSoftCallback.c
|
||||
dbRecStd_SRCS += devBoSoftCallback.c
|
||||
dbRecStd_SRCS += devCalcoutSoftCallback.c
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/* devAiSoftCallback.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 "dbChannel.h"
|
||||
#include "dbNotify.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "recGbl.h"
|
||||
#include "recSup.h"
|
||||
#include "devSup.h"
|
||||
#include "link.h"
|
||||
#include "aiRecord.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
|
||||
#define GET_OPTIONS (DBR_STATUS | DBR_TIME)
|
||||
|
||||
typedef struct devPvt {
|
||||
processNotify pn;
|
||||
CALLBACK callback;
|
||||
long options;
|
||||
int status;
|
||||
int smooth;
|
||||
struct {
|
||||
DBRstatus
|
||||
DBRtime
|
||||
epicsFloat64 value;
|
||||
} buffer;
|
||||
} devPvt;
|
||||
|
||||
|
||||
static void getCallback(processNotify *ppn, notifyGetType type)
|
||||
{
|
||||
aiRecord *prec = (aiRecord *)ppn->usrPvt;
|
||||
devPvt *pdevPvt = (devPvt *)prec->dpvt;
|
||||
long no_elements = 1;
|
||||
|
||||
if (ppn->status == notifyCanceled) {
|
||||
printf("devAiSoftCallback::getCallback notifyCanceled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(type == getFieldType);
|
||||
pdevPvt->status = dbChannelGetField(ppn->chan, DBR_DOUBLE,
|
||||
&pdevPvt->buffer, &pdevPvt->options, &no_elements, 0);
|
||||
}
|
||||
|
||||
static void doneCallback(processNotify *ppn)
|
||||
{
|
||||
aiRecord *prec = (aiRecord *)ppn->usrPvt;
|
||||
devPvt *pdevPvt = (devPvt *)prec->dpvt;
|
||||
|
||||
callbackRequestProcessCallback(&pdevPvt->callback, prec->prio, prec);
|
||||
}
|
||||
|
||||
static long add_record(dbCommon *pcommon)
|
||||
{
|
||||
aiRecord *prec = (aiRecord *)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,
|
||||
"devAiSoftCallback (add_record) Illegal INP field");
|
||||
return status;
|
||||
}
|
||||
|
||||
chan = dbChannelCreate(plink->value.pv_link.pvname);
|
||||
if (!chan) {
|
||||
long status = S_db_notFound;
|
||||
|
||||
recGblRecordError(status, (void *)prec,
|
||||
"devAiSoftCallback (add_record) link target not found");
|
||||
return status;
|
||||
}
|
||||
|
||||
pdevPvt = calloc(1, sizeof(*pdevPvt));
|
||||
if (!pdevPvt) {
|
||||
long status = S_db_noMemory;
|
||||
|
||||
recGblRecordError(status, (void *)prec,
|
||||
"devAiSoftCallback (add_record) out of memory, calloc() failed");
|
||||
return status;
|
||||
}
|
||||
ppn = &pdevPvt->pn;
|
||||
|
||||
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) {
|
||||
aiRecord *prec = (aiRecord *)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(aiRecord *prec)
|
||||
{
|
||||
/* INP must be CONSTANT or PN_LINK */
|
||||
switch (prec->inp.type) {
|
||||
case CONSTANT:
|
||||
if (recGblInitConstantLink(&prec->inp, DBF_DOUBLE, &prec->val))
|
||||
prec->udf = FALSE;
|
||||
break;
|
||||
case PN_LINK:
|
||||
/* Handled by add_record */
|
||||
break;
|
||||
default:
|
||||
recGblRecordError(S_db_badField, (void *)prec,
|
||||
"devAiSoftCallback (init_record) Illegal INP field");
|
||||
prec->pact = TRUE;
|
||||
return S_db_badField;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long read_ai(aiRecord *prec)
|
||||
{
|
||||
devPvt *pdevPvt = (devPvt *)prec->dpvt;
|
||||
|
||||
if (!prec->dpvt)
|
||||
return 2;
|
||||
|
||||
if (!prec->pact) {
|
||||
dbProcessNotify(&pdevPvt->pn);
|
||||
prec->pact = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pdevPvt->status) {
|
||||
recGblSetSevr(prec, READ_ALARM, INVALID_ALARM);
|
||||
pdevPvt->smooth = FALSE;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Apply smoothing algorithm */
|
||||
if (prec->smoo != 0.0 && pdevPvt->smooth)
|
||||
prec->val = prec->val * prec->smoo +
|
||||
pdevPvt->buffer.value * (1.0 - prec->smoo);
|
||||
else
|
||||
prec->val = pdevPvt->buffer.value;
|
||||
prec->udf = FALSE;
|
||||
pdevPvt->smooth = TRUE;
|
||||
|
||||
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 2;
|
||||
}
|
||||
|
||||
/* Create the dset for devAiSoftCallback */
|
||||
struct {
|
||||
dset common;
|
||||
DEVSUPFUN read_ai;
|
||||
DEVSUPFUN special_linconv;
|
||||
} devAiSoftCallback = {
|
||||
{6, NULL, init, init_record, NULL},
|
||||
read_ai,
|
||||
NULL
|
||||
};
|
||||
epicsExportAddress(dset, devAiSoftCallback);
|
||||
@@ -0,0 +1,223 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/* devBiSoftCallback.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 "dbChannel.h"
|
||||
#include "dbNotify.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "recGbl.h"
|
||||
#include "recSup.h"
|
||||
#include "devSup.h"
|
||||
#include "link.h"
|
||||
#include "biRecord.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
|
||||
#define GET_OPTIONS (DBR_STATUS | DBR_TIME)
|
||||
|
||||
typedef struct devPvt {
|
||||
processNotify pn;
|
||||
CALLBACK callback;
|
||||
long options;
|
||||
int status;
|
||||
struct {
|
||||
DBRstatus
|
||||
DBRtime
|
||||
epicsEnum16 value;
|
||||
} buffer;
|
||||
} devPvt;
|
||||
|
||||
|
||||
static void getCallback(processNotify *ppn,notifyGetType type)
|
||||
{
|
||||
biRecord *prec = (biRecord *)ppn->usrPvt;
|
||||
devPvt *pdevPvt = (devPvt *)prec->dpvt;
|
||||
long no_elements = 1;
|
||||
|
||||
if (ppn->status == notifyCanceled) {
|
||||
printf("devBiSoftCallback::getCallback notifyCanceled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(type == getFieldType);
|
||||
pdevPvt->status = dbChannelGetField(ppn->chan, DBR_ENUM,
|
||||
&pdevPvt->buffer, &pdevPvt->options, &no_elements, 0);
|
||||
}
|
||||
|
||||
static void doneCallback(processNotify *ppn)
|
||||
{
|
||||
biRecord *prec = (biRecord *)ppn->usrPvt;
|
||||
devPvt *pdevPvt = (devPvt *)prec->dpvt;
|
||||
|
||||
callbackRequestProcessCallback(&pdevPvt->callback, prec->prio, prec);
|
||||
}
|
||||
|
||||
static long add_record(dbCommon *pcommon)
|
||||
{
|
||||
biRecord *prec = (biRecord *)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,
|
||||
"devBiSoftCallback (add_record) Illegal INP field");
|
||||
return status;
|
||||
}
|
||||
|
||||
chan = dbChannelCreate(plink->value.pv_link.pvname);
|
||||
if (!chan) {
|
||||
long status = S_db_notFound;
|
||||
|
||||
recGblRecordError(status, (void *)prec,
|
||||
"devBiSoftCallback (add_record) link target not found");
|
||||
return status;
|
||||
}
|
||||
|
||||
pdevPvt = calloc(1, sizeof(*pdevPvt));
|
||||
if (!pdevPvt) {
|
||||
long status = S_db_noMemory;
|
||||
|
||||
recGblRecordError(status, (void *)prec,
|
||||
"devBiSoftCallback (add_record) out of memory, calloc() failed");
|
||||
return status;
|
||||
}
|
||||
ppn = &pdevPvt->pn;
|
||||
|
||||
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) {
|
||||
biRecord *prec = (biRecord *)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(biRecord *prec)
|
||||
{
|
||||
/* INP must be CONSTANT or PN_LINK */
|
||||
switch (prec->inp.type) {
|
||||
case CONSTANT:
|
||||
if (recGblInitConstantLink(&prec->inp, DBR_ENUM, &prec->val))
|
||||
prec->udf = FALSE;
|
||||
break;
|
||||
case PN_LINK:
|
||||
/* Handled by add_record */
|
||||
break;
|
||||
default:
|
||||
recGblRecordError(S_db_badField, (void *)prec,
|
||||
"devBiSoftCallback (init_record) Illegal INP field");
|
||||
prec->pact = TRUE;
|
||||
return S_db_badField;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long read_bi(biRecord *prec)
|
||||
{
|
||||
devPvt *pdevPvt = (devPvt *)prec->dpvt;
|
||||
|
||||
if (!prec->dpvt)
|
||||
return 2;
|
||||
|
||||
if (!prec->pact) {
|
||||
dbProcessNotify(&pdevPvt->pn);
|
||||
prec->pact = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pdevPvt->status) {
|
||||
recGblSetSevr(prec, READ_ALARM, INVALID_ALARM);
|
||||
return 2;
|
||||
}
|
||||
|
||||
prec->val = pdevPvt->buffer.value;
|
||||
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 2;
|
||||
}
|
||||
|
||||
/* Create the dset for devBiSoftCallback */
|
||||
struct {
|
||||
dset common;
|
||||
DEVSUPFUN read_bi;
|
||||
} devBiSoftCallback = {
|
||||
{5, NULL, init, init_record, NULL},
|
||||
read_bi
|
||||
};
|
||||
epicsExportAddress(dset, devBiSoftCallback);
|
||||
@@ -0,0 +1,223 @@
|
||||
/*************************************************************************\
|
||||
* 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 "dbChannel.h"
|
||||
#include "dbNotify.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "recGbl.h"
|
||||
#include "recSup.h"
|
||||
#include "devSup.h"
|
||||
#include "link.h"
|
||||
#include "longinRecord.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
|
||||
#define GET_OPTIONS (DBR_STATUS | DBR_TIME)
|
||||
|
||||
typedef struct devPvt {
|
||||
processNotify pn;
|
||||
CALLBACK callback;
|
||||
long options;
|
||||
int status;
|
||||
struct {
|
||||
DBRstatus
|
||||
DBRtime
|
||||
epicsInt32 value;
|
||||
} buffer;
|
||||
} devPvt;
|
||||
|
||||
|
||||
static void getCallback(processNotify *ppn, notifyGetType type)
|
||||
{
|
||||
longinRecord *prec = (longinRecord *)ppn->usrPvt;
|
||||
devPvt *pdevPvt = (devPvt *)prec->dpvt;
|
||||
long no_elements = 1;
|
||||
|
||||
if (ppn->status == notifyCanceled) {
|
||||
printf("devLiSoftCallback::getCallback notifyCanceled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(type == getFieldType);
|
||||
pdevPvt->status = dbChannelGetField(ppn->chan, DBR_LONG,
|
||||
&pdevPvt->buffer, &pdevPvt->options, &no_elements, 0);
|
||||
}
|
||||
|
||||
static void doneCallback(processNotify *ppn)
|
||||
{
|
||||
longinRecord *prec = (longinRecord *)ppn->usrPvt;
|
||||
devPvt *pdevPvt = (devPvt *)prec->dpvt;
|
||||
|
||||
callbackRequestProcessCallback(&pdevPvt->callback, prec->prio, prec);
|
||||
}
|
||||
|
||||
static long add_record(dbCommon *pcommon)
|
||||
{
|
||||
longinRecord *prec = (longinRecord *)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,
|
||||
"devLiSoftCallback (add_record) Illegal INP field");
|
||||
return status;
|
||||
}
|
||||
|
||||
chan = dbChannelCreate(plink->value.pv_link.pvname);
|
||||
if (!chan) {
|
||||
long status = S_db_notFound;
|
||||
|
||||
recGblRecordError(status, (void *)prec,
|
||||
"devLiSoftCallback (init_record) linked record not found");
|
||||
return status;
|
||||
}
|
||||
|
||||
pdevPvt = calloc(1, sizeof(*pdevPvt));
|
||||
if (!pdevPvt) {
|
||||
long status = S_db_noMemory;
|
||||
|
||||
recGblRecordError(status, (void *)prec,
|
||||
"devLiSoftCallback (add_record) out of memory, calloc() failed");
|
||||
return status;
|
||||
}
|
||||
ppn = &pdevPvt->pn;
|
||||
|
||||
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) {
|
||||
longinRecord *prec = (longinRecord *)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(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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
prec->val = pdevPvt->buffer.value;
|
||||
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 devLiSoftCallback */
|
||||
struct {
|
||||
dset common;
|
||||
DEVSUPFUN read_li;
|
||||
} devLiSoftCallback = {
|
||||
{5, NULL, init, init_record, NULL},
|
||||
read_li
|
||||
};
|
||||
epicsExportAddress(dset, devLiSoftCallback);
|
||||
@@ -0,0 +1,223 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/* devMbbiDirectSoftCallback.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 "dbChannel.h"
|
||||
#include "dbNotify.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "recGbl.h"
|
||||
#include "recSup.h"
|
||||
#include "devSup.h"
|
||||
#include "link.h"
|
||||
#include "mbbiDirectRecord.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
|
||||
#define GET_OPTIONS (DBR_STATUS | DBR_TIME)
|
||||
|
||||
typedef struct devPvt {
|
||||
processNotify pn;
|
||||
CALLBACK callback;
|
||||
long options;
|
||||
int status;
|
||||
struct {
|
||||
DBRstatus
|
||||
DBRtime
|
||||
epicsUInt16 value;
|
||||
} buffer;
|
||||
} devPvt;
|
||||
|
||||
|
||||
static void getCallback(processNotify *ppn, notifyGetType type)
|
||||
{
|
||||
mbbiDirectRecord *prec = (mbbiDirectRecord *)ppn->usrPvt;
|
||||
devPvt *pdevPvt = (devPvt *)prec->dpvt;
|
||||
long no_elements = 1;
|
||||
|
||||
if (ppn->status == notifyCanceled) {
|
||||
printf("devMbbiDirectSoftCallback::getCallback notifyCanceled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(type == getFieldType);
|
||||
pdevPvt->status = dbChannelGetField(ppn->chan, DBR_USHORT,
|
||||
&pdevPvt->buffer, &pdevPvt->options, &no_elements, 0);
|
||||
}
|
||||
|
||||
static void doneCallback(processNotify *ppn)
|
||||
{
|
||||
mbbiDirectRecord *prec = (mbbiDirectRecord *)ppn->usrPvt;
|
||||
devPvt *pdevPvt = (devPvt *)prec->dpvt;
|
||||
|
||||
callbackRequestProcessCallback(&pdevPvt->callback, prec->prio, prec);
|
||||
}
|
||||
|
||||
static long add_record(dbCommon *pcommon)
|
||||
{
|
||||
mbbiDirectRecord *prec = (mbbiDirectRecord *)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,
|
||||
"devMbbiDirectSoftCallback (add_record) Illegal INP field");
|
||||
return status;
|
||||
}
|
||||
|
||||
chan = dbChannelCreate(plink->value.pv_link.pvname);
|
||||
if (!chan) {
|
||||
long status = S_db_notFound;
|
||||
|
||||
recGblRecordError(status,(void *)prec,
|
||||
"devMbbiDirectSoftCallback (add_record) linked record not found");
|
||||
return status;
|
||||
}
|
||||
|
||||
pdevPvt = calloc(1, sizeof(*pdevPvt));
|
||||
if (!pdevPvt) {
|
||||
long status = S_db_noMemory;
|
||||
|
||||
recGblRecordError(status, (void *)prec,
|
||||
"devMbbiDirectSoftCallback (add_record) out of memory, calloc() failed");
|
||||
return status;
|
||||
}
|
||||
ppn = &pdevPvt->pn;
|
||||
|
||||
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) {
|
||||
mbbiDirectRecord *prec = (mbbiDirectRecord *)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(mbbiDirectRecord *prec)
|
||||
{
|
||||
/* INP must be CONSTANT or PN_LINK */
|
||||
switch (prec->inp.type) {
|
||||
case CONSTANT:
|
||||
if (recGblInitConstantLink(&prec->inp, DBR_ENUM, &prec->val))
|
||||
prec->udf = FALSE;
|
||||
break;
|
||||
case PN_LINK:
|
||||
/* Handled by add_record */
|
||||
break;
|
||||
default:
|
||||
recGblRecordError(S_db_badField, (void *)prec,
|
||||
"devMbbiSoftCallback (init_record) Illegal INP field");
|
||||
prec->pact = TRUE;
|
||||
return S_db_badField;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long read_mbbiDirect(mbbiDirectRecord *prec)
|
||||
{
|
||||
devPvt *pdevPvt = (devPvt *)prec->dpvt;
|
||||
|
||||
if (!prec->dpvt)
|
||||
return 2;
|
||||
|
||||
if (!prec->pact) {
|
||||
dbProcessNotify(&pdevPvt->pn);
|
||||
prec->pact = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pdevPvt->status) {
|
||||
recGblSetSevr(prec, READ_ALARM, INVALID_ALARM);
|
||||
return 2;
|
||||
}
|
||||
|
||||
prec->val = pdevPvt->buffer.value;
|
||||
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 2;
|
||||
}
|
||||
|
||||
/* Create the dset for devMbbiDirectSoftCallback */
|
||||
struct {
|
||||
dset common;
|
||||
DEVSUPFUN read_mbbiDirect;
|
||||
} devMbbiDirectSoftCallback = {
|
||||
{5, NULL, init, init_record, NULL},
|
||||
read_mbbiDirect
|
||||
};
|
||||
epicsExportAddress(dset, devMbbiDirectSoftCallback);
|
||||
@@ -0,0 +1,223 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/* devMbbiSoftCallback.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 "dbChannel.h"
|
||||
#include "dbNotify.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "recGbl.h"
|
||||
#include "recSup.h"
|
||||
#include "devSup.h"
|
||||
#include "link.h"
|
||||
#include "mbbiRecord.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
|
||||
#define GET_OPTIONS (DBR_STATUS | DBR_TIME)
|
||||
|
||||
typedef struct devPvt {
|
||||
processNotify pn;
|
||||
CALLBACK callback;
|
||||
long options;
|
||||
int status;
|
||||
struct {
|
||||
DBRstatus
|
||||
DBRtime
|
||||
epicsEnum16 value;
|
||||
} buffer;
|
||||
} devPvt;
|
||||
|
||||
|
||||
static void getCallback(processNotify *ppn, notifyGetType type)
|
||||
{
|
||||
mbbiRecord *prec = (mbbiRecord *)ppn->usrPvt;
|
||||
devPvt *pdevPvt = (devPvt *)prec->dpvt;
|
||||
long no_elements = 1;
|
||||
|
||||
if (ppn->status == notifyCanceled) {
|
||||
printf("devMbbiSoftCallback::getCallback notifyCanceled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(type == getFieldType);
|
||||
pdevPvt->status = dbChannelGetField(ppn->chan, DBR_ENUM,
|
||||
&pdevPvt->buffer, &pdevPvt->options, &no_elements, 0);
|
||||
}
|
||||
|
||||
static void doneCallback(processNotify *ppn)
|
||||
{
|
||||
mbbiRecord *prec = (mbbiRecord *)ppn->usrPvt;
|
||||
devPvt *pdevPvt = (devPvt *)prec->dpvt;
|
||||
|
||||
callbackRequestProcessCallback(&pdevPvt->callback, prec->prio, prec);
|
||||
}
|
||||
|
||||
static long add_record(dbCommon *pcommon)
|
||||
{
|
||||
mbbiRecord *prec = (mbbiRecord *)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,
|
||||
"devMbbiSoftCallback (add_record) Illegal INP field");
|
||||
return status;
|
||||
}
|
||||
|
||||
chan = dbChannelCreate(plink->value.pv_link.pvname);
|
||||
if (!chan) {
|
||||
long status = S_db_notFound;
|
||||
|
||||
recGblRecordError(status, (void *)prec,
|
||||
"devMbbiSoftCallback (add_record) linked record not found");
|
||||
return status;
|
||||
}
|
||||
|
||||
pdevPvt = calloc(1, sizeof(*pdevPvt));
|
||||
if (!pdevPvt) {
|
||||
long status = S_db_noMemory;
|
||||
|
||||
recGblRecordError(status, (void *)prec,
|
||||
"devMbbiSoftCallback (add_record) out of memory, calloc() failed");
|
||||
return status;
|
||||
}
|
||||
ppn = &pdevPvt->pn;
|
||||
|
||||
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) {
|
||||
mbbiRecord *prec = (mbbiRecord *)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(mbbiRecord *prec)
|
||||
{
|
||||
/* INP must be CONSTANT or PN_LINK */
|
||||
switch (prec->inp.type) {
|
||||
case CONSTANT:
|
||||
if (recGblInitConstantLink(&prec->inp, DBR_ENUM, &prec->val))
|
||||
prec->udf = FALSE;
|
||||
break;
|
||||
case PN_LINK:
|
||||
/* Handled by add_record */
|
||||
break;
|
||||
default:
|
||||
recGblRecordError(S_db_badField, (void *)prec,
|
||||
"devMbbiSoftCallback (init_record) Illegal INP field");
|
||||
prec->pact = TRUE;
|
||||
return S_db_badField;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long read_mbbi(mbbiRecord *prec)
|
||||
{
|
||||
devPvt *pdevPvt = (devPvt *)prec->dpvt;
|
||||
|
||||
if (!prec->dpvt)
|
||||
return 2;
|
||||
|
||||
if (!prec->pact) {
|
||||
dbProcessNotify(&pdevPvt->pn);
|
||||
prec->pact = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pdevPvt->status) {
|
||||
recGblSetSevr(prec, READ_ALARM, INVALID_ALARM);
|
||||
return 2;
|
||||
}
|
||||
|
||||
prec->val = pdevPvt->buffer.value;
|
||||
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 2;
|
||||
}
|
||||
|
||||
/* Create the dset for devMbbiSoftCallback */
|
||||
struct {
|
||||
dset common;
|
||||
DEVSUPFUN read_mbbi;
|
||||
} devMbbiSoftCallback = {
|
||||
{5, NULL, init, init_record, NULL},
|
||||
read_mbbi
|
||||
};
|
||||
epicsExportAddress(dset,devMbbiSoftCallback);
|
||||
@@ -0,0 +1,225 @@
|
||||
/*************************************************************************\
|
||||
* 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);
|
||||
@@ -27,12 +27,18 @@ device(mbbiDirect,CONSTANT,devMbbiDirectSoftRaw,"Raw Soft Channel")
|
||||
device(mbbo,CONSTANT,devMbboSoftRaw,"Raw Soft Channel")
|
||||
device(mbboDirect,CONSTANT,devMbboDirectSoftRaw,"Raw Soft Channel")
|
||||
|
||||
device(ai,CONSTANT,devAiSoftCallback,"Async Soft Channel")
|
||||
device(ao,CONSTANT,devAoSoftCallback,"Async Soft Channel")
|
||||
device(bi,CONSTANT,devBiSoftCallback,"Async Soft Channel")
|
||||
device(bo,CONSTANT,devBoSoftCallback,"Async Soft Channel")
|
||||
device(calcout,CONSTANT,devCalcoutSoftCallback,"Async Soft Channel")
|
||||
device(longin,CONSTANT,devLiSoftCallback,"Async Soft Channel")
|
||||
device(longout,CONSTANT,devLoSoftCallback,"Async Soft Channel")
|
||||
device(mbbi,CONSTANT,devMbbiSoftCallback,"Async Soft Channel")
|
||||
device(mbbiDirect,CONSTANT,devMbbiDirectSoftCallback,"Async Soft Channel")
|
||||
device(mbbo,CONSTANT,devMbboSoftCallback,"Async Soft Channel")
|
||||
device(mbboDirect,CONSTANT,devMbboDirectSoftCallback,"Async Soft Channel")
|
||||
device(stringin,CONSTANT,devSiSoftCallback,"Async Soft Channel")
|
||||
device(stringout,CONSTANT,devSoSoftCallback,"Async Soft Channel")
|
||||
|
||||
device(ai, INST_IO,devTimestampAI,"Soft Timestamp")
|
||||
|
||||
Reference in New Issue
Block a user