Merged process-get branch.

Seems to work, but not tested in depth.
This commit is contained in:
Andrew Johnson
2012-07-11 18:07:23 -05:00
21 changed files with 2013 additions and 431 deletions
+2 -2
View File
@@ -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
View File
@@ -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;
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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*/
+30 -23
View File
@@ -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 );
}
}
+8 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+12 -1
View File
@@ -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);
+5 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+7
View File
@@ -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
+233
View File
@@ -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);
+223
View File
@@ -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);
+223
View File
@@ -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);
+223
View File
@@ -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);
+223
View File
@@ -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);
+225
View File
@@ -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);
+6
View File
@@ -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")