Marty Kraimer's changes to support process-get operations.

This commit is contained in:
Andrew Johnson
2009-12-28 20:37:09 -06:00
parent 2b9d66273c
commit 0563044097
17 changed files with 1354 additions and 375 deletions
+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")
+307 -227
View File
@@ -46,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 {
typedef struct notifyPvt {
ELLNODE node; /*For free list*/
long magic;
short state;
CALLBACK callback;
ELLLIST waitList; /*list of records for current putNotify*/
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;
@@ -87,12 +87,11 @@ 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 notifyCallback(CALLBACK *pcallback);
static void putNotifyCommon(putNotify *ppn,dbCommon *precord);
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);
#define ellSafeAdd(list,listnode) \
{ \
@@ -108,176 +107,193 @@ 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);
/*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);
dbScanUnlock(precord);
(*ppn->userCallback)(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 (ppn->requestType == processGetRequest ||
ppn->requestType == putProcessGetRequest) {
ppn->getCallback(ppn, getFieldType);
}
if(!pputNotifyPvt->cancelWait && !pputNotifyPvt->userCallbackWait) {
putNotifyCleanup(ppn);
dbScanUnlock(precord);
ppn->doneCallback(ppn);
epicsMutexMustLock(pnotifyGlobal->lock);
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 (!pnotifyPvt->cancelWait && !pnotifyPvt->userCallbackWait) {
notifyCleanup(ppn);
epicsMutexUnlock(pnotifyGlobal->lock);
return;
}
if(pputNotifyPvt->cancelWait) {
pputNotifyPvt->cancelWait = 0;
epicsEventSignal(pputNotifyPvt->cancelEvent);
if (pnotifyPvt->cancelWait) {
pnotifyPvt->cancelWait = 0;
epicsEventSignal(pnotifyPvt->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=0;
dbFldDes *pfldDes = ppn->paddr->pfldDes;
putNotifyPvt *pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt;
dbFldDes *pfldDes=(dbFldDes *)(ppn->paddr->pfldDes);
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;
if (precord->ppn && 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);
} else if (precord->ppn) {
assert(precord->ppn == ppn);
assert(pnotifyPvt->state == notifyRestartCallbackRequested);
}
if(precord->pact) {
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=dbPut(ppn->paddr,ppn->dbrType,ppn->pbuffer,ppn->nRequest);
ppn->status = (status==0) ? putNotifyOK : putNotifyError;
if (ppn->requestType == putProcessRequest ||
ppn->requestType == putProcessGetRequest) {
/*check for putField disabled*/
if (precord->disp && ((void *)&precord->disp != ppn->paddr->pfield)) {
ppn->putCallback(ppn, putDisabledType);
} else {
didPut = ppn->putCallback(ppn, putType);
}
}
/* Check to see if dbProcess should not be called */
if(!status /*dont process if dbPut returned error */
&&((ppn->paddr->pfield==(void *)&precord->proc) /*If PROC call dbProcess*/
|| (pfldDes->process_passive && precord->scan==0))) {
if (didPut && ((ppn->paddr->pfield == (void *)&precord->proc)
|| (pfldDes->process_passive && precord->scan==0))) doProcess = 1;
if (!doProcess && ppn->requestType == processGetRequest) {
if (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 = ppn->paddr->precord;
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;
pnotifyGlobal = dbCalloc(1,sizeof(notifyGlobal));
@@ -285,104 +301,111 @@ void epicsShareAPI dbPutNotifyInit(void)
ellInit(&pnotifyGlobal->freeList);
}
void epicsShareAPI dbPutNotify(putNotify *ppn)
void epicsShareAPI dbProcessNotify(processNotify *ppn)
{
dbCommon *precord = ppn->paddr->precord;
short dbfType = ppn->paddr->field_type;
long status=0;
putNotifyPvt *pputNotifyPvt;
notifyPvt *pnotifyPvt;
assert(precord);
/*check for putField disabled*/
if(precord->disp) {
if((void *)(&precord->disp) != ppn->paddr->pfield) {
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=dbPutField(ppn->paddr,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 for putField disabled*/
if (precord->disp &&((void *)(&precord->disp) != ppn->paddr->pfield)) {
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 = ppn->paddr->precord;
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;
state = pnotifyPvt->state;
/*If callback is scheduled or active wait for it to complete*/
if(state==putNotifyUserCallbackRequested
|| state==putNotifyRestartCallbackRequested
|| state==putNotifyUserCallbackActive) {
pputNotifyPvt->cancelWait = 1;
if(state==notifyUserCallbackRequested
|| state==notifyRestartCallbackRequested
|| state==notifyUserCallbackActive) {
pnotifyPvt->cancelWait = 1;
epicsMutexUnlock(pnotifyGlobal->lock);
dbScanUnlock(precord);
epicsEventWait(pputNotifyPvt->cancelEvent);
epicsEventWait(pnotifyPvt->cancelEvent);
epicsMutexMustLock(pnotifyGlobal->lock);
putNotifyCleanup(ppn);
notifyCleanup(ppn);
epicsMutexUnlock(pnotifyGlobal->lock);
return;
}
switch(state) {
case putNotifyNotActive: break;
case putNotifyWaitForRestart:
case notifyNotActive: break;
case notifyWaitForRestart:
assert(precord->ppn);
assert(precord->ppn!=ppn);
ellSafeDelete(&precord->ppnr->restartList,&ppn->restartNode);
break;
case putNotifyRestartInProgress:
case putNotifyPutInProgress:
case notifyRestartInProgress:
case notifyProcessInProgress:
{ /*Take all records out of wait list */
putNotifyRecord *ppnrWait;
processNotifyRecord *ppnrWait;
while((ppnrWait = (putNotifyRecord *)ellFirst(&pputNotifyPvt->waitList))){
ellSafeDelete(&pputNotifyPvt->waitList,&ppnrWait->waitNode);
while((ppnrWait = (processNotifyRecord *)ellFirst(&pnotifyPvt->waitList))){
ellSafeDelete(&pnotifyPvt->waitList,&ppnrWait->waitNode);
restartCheck(ppnrWait);
}
}
@@ -391,36 +414,36 @@ void epicsShareAPI dbNotifyCancel(putNotify *ppn)
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");
}
@@ -429,52 +452,103 @@ 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!=ppn->paddr->precord)) {
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 *psavevalue;
}tpnInfo;
static void dbtpnCallback(putNotify *ppn)
static int putCallback(processNotify *ppn,notifyPutType type) {
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 = dbPutField(ppn->paddr,DBR_STRING,ptpnInfo->psavevalue,1);
break;
case putType:
status = dbPut(ppn->paddr,DBR_STRING,ptpnInfo->psavevalue,1);
break;
}
if(status!=0) ppn->status = notifyError;
return 1;
}
static void getCallback(processNotify *ppn,notifyGetType type)
{
putNotifyStatus status = ppn->status;
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 = dbGetField(ppn->paddr,DBR_STRING,ptpnInfo->psavevalue,
&options,&no_elements,0);
break;
case getType:
status = dbGet(ppn->paddr,DBR_STRING,ptpnInfo->psavevalue,
&options,&no_elements,0);
break;
}
if(status!=0) {
ppn->status = notifyError;
printf("dbtpn:getCallback error\n");
} else {
printf("dbtpn:getCallback value %s\n",ptpnInfo->psavevalue);
}
}
static void doneCallback(processNotify *ppn)
{
notifyStatus status = ppn->status;
tpnInfo *ptpnInfo = (tpnInfo *)ppn->usrPvt;
if(status==0)
printf("dbtpnCallback: success record=%s\n",ppn->paddr->precord->name);
else
printf("%s dbtpnCallback putNotify.status %d\n",ppn->paddr->precord->name,(int)status);
printf("%s dbtpnCallback processNotify.status %d\n",ppn->paddr->precord->name,(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);
@@ -488,30 +562,35 @@ long epicsShareAPI dbtpn(char *pname,char *pvalue)
long status;
tpnInfo *ptpnInfo;
DBADDR *pdbaddr=NULL;
putNotify *ppn=NULL;
processNotify *ppn=NULL;
char *psavevalue;
int len;
int len = 80;
len = strlen(pvalue);
if(pvalue) len = strlen(pvalue);
/*allocate space for value immediately following DBADDR*/
pdbaddr = dbCalloc(1,sizeof(DBADDR) + len+1);
psavevalue = (char *)(pdbaddr + 1);
strcpy(psavevalue,pvalue);
if(pvalue) strcpy(psavevalue,pvalue);
status = dbNameToAddr(pname,pdbaddr);
if(status) {
errMessage(status, "dbtpn: dbNameToAddr");
free((void *)pdbaddr);
return(-1);
}
ppn = dbCalloc(1,sizeof(putNotify));
ppn = dbCalloc(1,sizeof(processNotify));
if(pvalue) {
ppn->requestType = putProcessRequest;
} else {
ppn->requestType = processGetRequest;
}
ppn->paddr = pdbaddr;
ppn->pbuffer = psavevalue;
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);
ptpnInfo->psavevalue = psavevalue;
ppn->usrPvt = ptpnInfo;
epicsThreadCreate("dbtpn",epicsThreadPriorityHigh,
epicsThreadGetStackSize(epicsThreadStackMedium),
@@ -525,49 +604,50 @@ int epicsShareAPI dbNotifyDump(void)
dbRecordType *pdbRecordType;
dbRecordNode *pdbRecordNode;
dbCommon *precord;
putNotify *ppn;
putNotify *ppnRestart;
putNotifyRecord *ppnrWait;
processNotify *ppn;
processNotify *ppnRestart;
processNotifyRecord *ppnr;
int itry;
for(itry=0; itry<100; itry++) {
for (itry=0; itry<100; itry++) {
lockStatus = epicsMutexTryLock(pnotifyGlobal->lock);
if(lockStatus==epicsMutexLockOK) break;
epicsThreadSleep(.05);
}
for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList);
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;
notifyPvt *pnotifyPvt;
precord = pdbRecordNode->precord;
if (!precord->name[0] ||
pdbRecordNode->flags & DBRN_FLAGS_ISALIAS)
continue;
if(!precord->ppn) continue;
if(!precord->ppnr) continue;
if(precord->ppn->paddr->precord != 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);
if (ppn) {
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",ppnRestart->paddr->precord->name);
ppnRestart = (processNotify *)ellNext(
&ppnRestart->restartNode.node);
}
}
}
}
if(lockStatus==epicsMutexLockOK) epicsMutexUnlock(pnotifyGlobal->lock);
return(0);
return 0;
}
+99 -52
View File
@@ -20,7 +20,7 @@
#ifdef __cplusplus
/* for brain dead C++ compilers */
struct dbCommon;
struct putNotify;
struct processNotify;
extern "C" {
#endif
@@ -30,36 +30,54 @@ typedef struct ellCheckNode{
}ellCheckNode;
typedef enum {
putNotifyOK,
putNotifyCanceled,
putNotifyError,
putNotifyPutDisabled
}putNotifyStatus;
processRequest,
putProcessRequest,
processGetRequest,
putProcessGetRequest
}notifyRequestType;
typedef struct putNotify{
typedef enum {
putDisabledType,
putFieldType,
putType
}notifyPutType;
typedef enum {
getFieldType,
getType
}notifyGetType;
typedef enum {
notifyOK,
notifyCanceled,
notifyError,
notifyPutDisabled
}notifyStatus;
typedef struct processNotify {
/* following fields are for private use by dbNotify implementation */
ellCheckNode restartNode;
/*The following members MUST be set by user*/
void (*userCallback)(struct putNotify *);
void *pnotifyPvt; /*for private use of dbNotify*/
/* 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 dbAddr *paddr; /*dbAddr set by dbNameToAddr*/
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;
int (*putCallback)(struct processNotify *,notifyPutType type);
void (*getCallback)(struct processNotify *,notifyGetType type);
void (*doneCallback)(struct processNotify *);
void *usrPvt; /*for private use of user*/
}processNotify;
/* 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);
/*dbPutNotifyMapType convience function for old database access*/
epicsShareFunc int epicsShareAPI dbPutNotifyMapType (putNotify *ppn, short oldtype);
/* dbProcessNotify and dbNotifyCancel are called by user*/
epicsShareFunc void epicsShareAPI dbProcessNotify(processNotify *pprocessNotify);
epicsShareFunc void epicsShareAPI dbNotifyCancel(processNotify *pprocessNotify);
/* dbPutNotifyInit called by iocInit */
epicsShareFunc void epicsShareAPI dbPutNotifyInit(void);
/* dbProcessNotifyInit called by iocInit */
epicsShareFunc void epicsShareAPI dbProcessNotifyInit(void);
/*dbNotifyAdd called by dbScanPassive and dbScanLink*/
epicsShareFunc void epicsShareAPI dbNotifyAdd(
@@ -67,29 +85,61 @@ 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. Dont 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.
* paddr - This is typically set via a call to dbNameToAddr.
* 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,19 +151,16 @@ 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
}
+28 -20
View File
@@ -52,7 +52,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 +64,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 +88,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 +124,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 +175,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.paddr = &addr;
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 ();
+44 -22
View File
@@ -994,39 +994,61 @@ int epicsShareAPI db_put_field(struct dbAddr *paddr, 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 = dbPutField(ppn->paddr,dbrType,psrc,no_elements);
break;
case putType:
status = dbPut(ppn->paddr,dbrType,psrc,no_elements);
break;
}
if (status) ppn->status = notifyError;
return 1;
}
+23 -20
View File
@@ -637,29 +637,36 @@ static void print_returned(type,count,pbuffer)
typedef struct tpnInfo {
epicsEventId callbackDone;
putNotify *ppn;
processNotify *ppn;
char *psavevalue;
}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->psavevalue,1);
}
static void doneCallback(processNotify *ppn)
{
struct dbAddr *pdbaddr = (struct dbAddr *)ppn->paddr;
notifyStatus status = ppn->status;
tpnInfo *ptpnInfo = (tpnInfo *)ppn->usrPvt;
putNotifyStatus status = ppn->status;
char *pname = pdbaddr->precord->name;
char *pname = ppn->paddr->precord->name;
if(status==0)
printf("tpnCallback: success record=%s\n",pname);
printf("tpnCallback: success record=%s\n",pname);
else
printf("%s tpnCallback status = %d\n",pname,status);
printf("%s tpnCallback 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);
@@ -674,7 +681,7 @@ int epicsShareAPI tpn(char *pname,char *pvalue)
long status;
tpnInfo *ptpnInfo;
struct dbAddr *pdbaddr=NULL;
putNotify *ppn=NULL;
processNotify *ppn=NULL;
char *psavevalue;
int len;
@@ -699,20 +706,15 @@ int epicsShareAPI tpn(char *pname,char *pvalue)
free((void *)pdbaddr);
return(-1);
}
ppn = calloc(1,sizeof(putNotify));
if(!pdbaddr) {
ppn = calloc(1,sizeof(processNotify));
if(!ppn) {
printf("calloc failed\n");
return(-1);
}
ppn->requestType = putProcessRequest;
ppn->paddr = pdbaddr;
ppn->pbuffer = psavevalue;
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");
@@ -720,6 +722,7 @@ int epicsShareAPI tpn(char *pname,char *pvalue)
}
ptpnInfo->ppn = ppn;
ptpnInfo->callbackDone = epicsEventCreate(epicsEventEmpty);
ptpnInfo->psavevalue = psavevalue;
ppn->usrPvt = ptpnInfo;
epicsThreadCreate("tpn",epicsThreadPriorityHigh,
epicsThreadGetStackSize(epicsThreadStackMedium),
+1 -1
View File
@@ -140,7 +140,7 @@ int iocBuild(void)
errlogPrintf("iocBuild: asInit Failed.\n");
return -1;
}
dbPutNotifyInit();
dbProcessNotifyInit();
epicsThreadSleep(.5);
initHookAnnounce(initHookAfterScanInit);
+51 -26
View File
@@ -57,7 +57,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
@@ -77,8 +77,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;
@@ -1390,11 +1395,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;
@@ -1460,7 +1487,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{
@@ -1593,14 +1620,17 @@ static struct rsrv_put_notify *
pNotify = (RSRVPUTNOTIFY *)
freeListCalloc ( rsrvPutNotifyFreeList );
if ( pNotify ) {
pNotify->dbPutNotify.pbuffer =
pNotify->pbuffer =
&pNotify->dbrScalarValue;
pNotify->valueSize =
sizeof (pNotify->dbrScalarValue);
pNotify->dbPutNotify.usrPvt = pciu;
pNotify->dbPutNotify.paddr = &pciu->addr;
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 {
@@ -1622,10 +1652,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;
}
@@ -1633,7 +1663,7 @@ static int rsrvExpandPutNotify (
/*
* revert back to the embedded union
*/
pNotify->dbPutNotify.pbuffer =
pNotify->pbuffer =
&pNotify->dbrScalarValue;
pNotify->valueSize =
sizeof (pNotify->dbrScalarValue);
@@ -1694,7 +1724,7 @@ void rsrvFreePutNotify ( client *pClient,
if ( pNotify->valueSize >
sizeof(pNotify->dbrScalarValue) ) {
free ( pNotify->dbPutNotify.pbuffer );
free ( pNotify->pbuffer );
}
freeListFree ( rsrvPutNotifyFreeList, pNotify );
}
@@ -1768,7 +1798,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);
}
@@ -1801,10 +1831,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);
@@ -1812,12 +1842,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,
@@ -1825,7 +1850,7 @@ static int write_notify_action ( caHdrLargeArray *mp, void *pPayload,
pciu->client->pHostName ? pciu->client->pHostName : "",
(void *) &pciu->addr );
dbPutNotify(&pciu->pPutNotify->dbPutNotify);
dbProcessNotify(&pciu->pPutNotify->dbPutNotify);
return RSRV_OK;
}
+6
View File
@@ -42,6 +42,12 @@ 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 += devMbbiSoftCallback.c
dbRecStd_SRCS += devSiSoftCallback.c
dbRecStd_SRCS += devAoSoftCallback.c
dbRecStd_SRCS += devBoSoftCallback.c
dbRecStd_SRCS += devCalcoutSoftCallback.c
+155
View File
@@ -0,0 +1,155 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, 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 */
/*
* Author: Marty Kraimer
* Date: 23APR2008
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "callback.h"
#include "cantProceed.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "dbNotify.h"
#include "recGbl.h"
#include "recSup.h"
#include "devSup.h"
#include "link.h"
#include "aiRecord.h"
#include "epicsExport.h"
/* Create the dset for devAiSoftCallback */
static long init_record();
static long read_ai();
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_ai;
DEVSUPFUN special_linconv;
}devAiSoftCallback={
6,
NULL,
NULL,
init_record,
NULL,
read_ai,
NULL};
epicsExportAddress(dset,devAiSoftCallback);
typedef struct notifyInfo {
processNotify *ppn;
CALLBACK *pcallback;
double value;
int status;
}notifyInfo;
static void getCallback(processNotify *ppn,notifyGetType type)
{
struct aiRecord *pai = (struct aiRecord *)ppn->usrPvt;
notifyInfo *pnotifyInfo = (notifyInfo *)pai->dpvt;
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 = dbGetField(ppn->paddr,DBR_DOUBLE,&pnotifyInfo->value,
&options,&no_elements,0);
break;
case getType:
status = dbGet(ppn->paddr,DBR_DOUBLE,&pnotifyInfo->value,
&options,&no_elements,0);
break;
}
pnotifyInfo->status = status;
}
static void doneCallback(processNotify *ppn)
{
struct aiRecord *pai = (struct aiRecord *)ppn->usrPvt;
notifyInfo *pnotifyInfo = (notifyInfo *)pai->dpvt;
callbackRequestProcessCallback(pnotifyInfo->pcallback,pai->prio,pai);
}
static long init_record(struct aiRecord *pai)
{
DBLINK *plink = &pai->inp;
struct instio *pinstio;
char *pvname;
DBADDR *pdbaddr=NULL;
long status;
notifyInfo *pnotifyInfo;
CALLBACK *pcallback;
processNotify *ppn=NULL;
if(plink->type!=INST_IO) {
recGblRecordError(S_db_badField,(void *)pai,
"devAiSoftCallback (init_record) Illegal INP field");
pai->pact=TRUE;
return(S_db_badField);
}
pinstio=(struct instio*)&(plink->value);
pvname = pinstio->string;
pdbaddr = callocMustSucceed(1, sizeof(*pdbaddr),
"devAiSoftCallback::init_record");
status = dbNameToAddr(pvname,pdbaddr);
if(status) {
recGblRecordError(status,(void *)pai,
"devAiSoftCallback (init_record) linked record not found");
pai->pact=TRUE;
return(status);
}
pnotifyInfo = callocMustSucceed(1, sizeof(*pnotifyInfo),
"devAiSoftCallback::init_record");
pcallback = callocMustSucceed(1, sizeof(*pcallback),
"devAiSoftCallback::init_record");
ppn = callocMustSucceed(1, sizeof(*ppn),
"devAiSoftCallback::init_record");
pnotifyInfo->ppn = ppn;
pnotifyInfo->pcallback = pcallback;
ppn->usrPvt = pai;
ppn->paddr = pdbaddr;
ppn->getCallback = getCallback;
ppn->doneCallback = doneCallback;
ppn->requestType = processGetRequest;
pai->dpvt = pnotifyInfo;
return 0;
}
static long read_ai(aiRecord *pai)
{
notifyInfo *pnotifyInfo = (notifyInfo *)pai->dpvt;
if(pai->pact) {
if(pnotifyInfo->status) {
recGblSetSevr(pai,READ_ALARM,INVALID_ALARM);
return(2);
}
pai->val = pnotifyInfo->value;
pai->udf = FALSE;
return(2);
}
dbProcessNotify(pnotifyInfo->ppn);
pai->pact = TRUE;
return(0);
}
+155
View File
@@ -0,0 +1,155 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, 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 */
/*
* Author: Marty Kraimer
* Date: 23APR2008
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "callback.h"
#include "cantProceed.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "dbNotify.h"
#include "recGbl.h"
#include "recSup.h"
#include "devSup.h"
#include "link.h"
#include "biRecord.h"
#include "epicsExport.h"
/* Create the dset for devBiSoftCallback */
static long init_record();
static long read_bi();
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_bi;
DEVSUPFUN special_linconv;
}devBiSoftCallback={
6,
NULL,
NULL,
init_record,
NULL,
read_bi,
NULL};
epicsExportAddress(dset,devBiSoftCallback);
typedef struct notifyInfo {
processNotify *ppn;
CALLBACK *pcallback;
unsigned short value;
int status;
}notifyInfo;
static void getCallback(processNotify *ppn,notifyGetType type)
{
struct biRecord *pbi = (struct biRecord *)ppn->usrPvt;
notifyInfo *pnotifyInfo = (notifyInfo *)pbi->dpvt;
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 = dbGetField(ppn->paddr,DBR_USHORT,&pnotifyInfo->value,
&options,&no_elements,0);
break;
case getType:
status = dbGet(ppn->paddr,DBR_USHORT,&pnotifyInfo->value,
&options,&no_elements,0);
break;
}
pnotifyInfo->status = status;
}
static void doneCallback(processNotify *ppn)
{
struct biRecord *pbi = (struct biRecord *)ppn->usrPvt;
notifyInfo *pnotifyInfo = (notifyInfo *)pbi->dpvt;
callbackRequestProcessCallback(pnotifyInfo->pcallback,pbi->prio,pbi);
}
static long init_record(struct biRecord *pbi)
{
DBLINK *plink = &pbi->inp;
struct instio *pinstio;
char *pvname;
DBADDR *pdbaddr=NULL;
long status;
notifyInfo *pnotifyInfo;
CALLBACK *pcallback;
processNotify *ppn=NULL;
if(plink->type!=INST_IO) {
recGblRecordError(S_db_badField,(void *)pbi,
"devBiSoftCallback (init_record) linked record not found");
pbi->pact=TRUE;
return(S_db_badField);
}
pinstio=(struct instio*)&(plink->value);
pvname = pinstio->string;
pdbaddr = callocMustSucceed(1, sizeof(*pdbaddr),
"devBiSoftCallback::init_record");
status = dbNameToAddr(pvname,pdbaddr);
if(status) {
recGblRecordError(status,(void *)pbi,
"devBiSoftCallback (init_record) Illegal INP field");
pbi->pact=TRUE;
return(status);
}
pnotifyInfo = callocMustSucceed(1, sizeof(*pnotifyInfo),
"devBiSoftCallback::init_record");
pcallback = callocMustSucceed(1, sizeof(*pcallback),
"devBiSoftCallback::init_record");
ppn = callocMustSucceed(1, sizeof(*ppn),
"devBiSoftCallback::init_record");
pnotifyInfo->ppn = ppn;
pnotifyInfo->pcallback = pcallback;
ppn->usrPvt = pbi;
ppn->paddr = pdbaddr;
ppn->getCallback = getCallback;
ppn->doneCallback = doneCallback;
ppn->requestType = processGetRequest;
pbi->dpvt = pnotifyInfo;
return 0;
}
static long read_bi(biRecord *pbi)
{
notifyInfo *pnotifyInfo = (notifyInfo *)pbi->dpvt;
if(pbi->pact) {
if(pnotifyInfo->status) {
recGblSetSevr(pbi,READ_ALARM,INVALID_ALARM);
return(2);
}
pbi->val = pnotifyInfo->value;
pbi->udf = FALSE;
return(2);
}
dbProcessNotify(pnotifyInfo->ppn);
pbi->pact = TRUE;
return(0);
}
+155
View File
@@ -0,0 +1,155 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, 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 */
/*
* Author: Marty Kraimer
* Date: 23APR2008
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "callback.h"
#include "cantProceed.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "dbNotify.h"
#include "recGbl.h"
#include "recSup.h"
#include "devSup.h"
#include "link.h"
#include "longinRecord.h"
#include "epicsExport.h"
/* Create the dset for devLiSoftCallback */
static long init_record();
static long read_li();
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_li;
DEVSUPFUN special_linconv;
}devLiSoftCallback={
6,
NULL,
NULL,
init_record,
NULL,
read_li,
NULL};
epicsExportAddress(dset,devLiSoftCallback);
typedef struct notifyInfo {
processNotify *ppn;
CALLBACK *pcallback;
long value;
int status;
}notifyInfo;
static void getCallback(processNotify *ppn,notifyGetType type)
{
struct longinRecord *pli = (struct longinRecord *)ppn->usrPvt;
notifyInfo *pnotifyInfo = (notifyInfo *)pli->dpvt;
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 = dbGetField(ppn->paddr,DBR_LONG,&pnotifyInfo->value,
&options,&no_elements,0);
break;
case getType:
status = dbGet(ppn->paddr,DBR_LONG,&pnotifyInfo->value,
&options,&no_elements,0);
break;
}
pnotifyInfo->status = status;
}
static void doneCallback(processNotify *ppn)
{
struct longinRecord *pli = (struct longinRecord *)ppn->usrPvt;
notifyInfo *pnotifyInfo = (notifyInfo *)pli->dpvt;
callbackRequestProcessCallback(pnotifyInfo->pcallback,pli->prio,pli);
}
static long init_record(struct longinRecord *pli)
{
DBLINK *plink = &pli->inp;
struct instio *pinstio;
char *pvname;
DBADDR *pdbaddr=NULL;
long status;
notifyInfo *pnotifyInfo;
CALLBACK *pcallback;
processNotify *ppn=NULL;
if(plink->type!=INST_IO) {
recGblRecordError(S_db_badField,(void *)pli,
"devLiSoftCallback (init_record) linked record not found");
pli->pact=TRUE;
return(S_db_badField);
}
pinstio=(struct instio*)&(plink->value);
pvname = pinstio->string;
pdbaddr = callocMustSucceed(1, sizeof(*pdbaddr),
"devLiSoftCallback::init_record");
status = dbNameToAddr(pvname,pdbaddr);
if(status) {
recGblRecordError(status,(void *)pli,
"devLiSoftCallback (init_record) Illegal INP field");
pli->pact=TRUE;
return(status);
}
pnotifyInfo = callocMustSucceed(1, sizeof(*pnotifyInfo),
"devLiSoftCallback::init_record");
pcallback = callocMustSucceed(1, sizeof(*pcallback),
"devLiSoftCallback::init_record");
ppn = callocMustSucceed(1, sizeof(*ppn),
"devLiSoftCallback::init_record");
pnotifyInfo->ppn = ppn;
pnotifyInfo->pcallback = pcallback;
ppn->usrPvt = pli;
ppn->paddr = pdbaddr;
ppn->getCallback = getCallback;
ppn->doneCallback = doneCallback;
ppn->requestType = processGetRequest;
pli->dpvt = pnotifyInfo;
return 0;
}
static long read_li(longinRecord *pli)
{
notifyInfo *pnotifyInfo = (notifyInfo *)pli->dpvt;
if(pli->pact) {
if(pnotifyInfo->status) {
recGblSetSevr(pli,READ_ALARM,INVALID_ALARM);
return(pnotifyInfo->status);
}
pli->val = pnotifyInfo->value;
pli->udf = FALSE;
return(0);
}
dbProcessNotify(pnotifyInfo->ppn);
pli->pact = TRUE;
return(0);
}
+155
View File
@@ -0,0 +1,155 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, 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 */
/*
* Author: Marty Kraimer
* Date: 23APR2008
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "callback.h"
#include "cantProceed.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "dbNotify.h"
#include "recGbl.h"
#include "recSup.h"
#include "devSup.h"
#include "link.h"
#include "mbbiRecord.h"
#include "epicsExport.h"
/* Create the dset for devMbbiSoftCallback */
static long init_record();
static long read_mbbi();
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_mbbi;
DEVSUPFUN special_linconv;
}devMbbiSoftCallback={
6,
NULL,
NULL,
init_record,
NULL,
read_mbbi,
NULL};
epicsExportAddress(dset,devMbbiSoftCallback);
typedef struct notifyInfo {
processNotify *ppn;
CALLBACK *pcallback;
unsigned short value;
int status;
}notifyInfo;
static void getCallback(processNotify *ppn,notifyGetType type)
{
struct mbbiRecord *pmbbi = (struct mbbiRecord *)ppn->usrPvt;
notifyInfo *pnotifyInfo = (notifyInfo *)pmbbi->dpvt;
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 = dbGetField(ppn->paddr,DBR_USHORT,&pnotifyInfo->value,
&options,&no_elements,0);
break;
case getType:
status = dbGet(ppn->paddr,DBR_USHORT,&pnotifyInfo->value,
&options,&no_elements,0);
break;
}
pnotifyInfo->status = status;
}
static void doneCallback(processNotify *ppn)
{
struct mbbiRecord *pmbbi = (struct mbbiRecord *)ppn->usrPvt;
notifyInfo *pnotifyInfo = (notifyInfo *)pmbbi->dpvt;
callbackRequestProcessCallback(pnotifyInfo->pcallback,pmbbi->prio,pmbbi);
}
static long init_record(struct mbbiRecord *pmbbi)
{
DBLINK *plink = &pmbbi->inp;
struct instio *pinstio;
char *pvname;
DBADDR *pdbaddr=NULL;
long status;
notifyInfo *pnotifyInfo;
CALLBACK *pcallback;
processNotify *ppn=NULL;
if(plink->type!=INST_IO) {
recGblRecordError(S_db_badField,(void *)pmbbi,
"devMbbiSoftCallback (init_record) linked record not found");
pmbbi->pact=TRUE;
return(S_db_badField);
}
pinstio=(struct instio*)&(plink->value);
pvname = pinstio->string;
pdbaddr = callocMustSucceed(1, sizeof(*pdbaddr),
"devMbbiSoftCallback::init_record");
status = dbNameToAddr(pvname,pdbaddr);
if(status) {
recGblRecordError(status,(void *)pmbbi,
"devMbbiSoftCallback (init_record) Illegal INP field");
pmbbi->pact=TRUE;
return(status);
}
pnotifyInfo = callocMustSucceed(1, sizeof(*pnotifyInfo),
"devMbbiSoftCallback::init_record");
pcallback = callocMustSucceed(1, sizeof(*pcallback),
"devMbbiSoftCallback::init_record");
ppn = callocMustSucceed(1, sizeof(*ppn),
"devMbbiSoftCallback::init_record");
pnotifyInfo->ppn = ppn;
pnotifyInfo->pcallback = pcallback;
ppn->usrPvt = pmbbi;
ppn->paddr = pdbaddr;
ppn->getCallback = getCallback;
ppn->doneCallback = doneCallback;
ppn->requestType = processGetRequest;
pmbbi->dpvt = pnotifyInfo;
return 0;
}
static long read_mbbi(mbbiRecord *pmbbi)
{
notifyInfo *pnotifyInfo = (notifyInfo *)pmbbi->dpvt;
if(pmbbi->pact) {
if(pnotifyInfo->status) {
recGblSetSevr(pmbbi,READ_ALARM,INVALID_ALARM);
return(2);
}
pmbbi->val = pnotifyInfo->value;
pmbbi->udf = FALSE;
return(2);
}
dbProcessNotify(pnotifyInfo->ppn);
pmbbi->pact = TRUE;
return(0);
}
+155
View File
@@ -0,0 +1,155 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, 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 */
/*
* Author: Marty Kraimer
* Date: 23APR2008
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "callback.h"
#include "cantProceed.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "dbNotify.h"
#include "recGbl.h"
#include "recSup.h"
#include "devSup.h"
#include "link.h"
#include "stringinRecord.h"
#include "epicsExport.h"
/* Create the dset for devSiSoftCallback */
static long init_record();
static long read_stringin();
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_stringin;
DEVSUPFUN special_linconv;
}devSiSoftCallback={
6,
NULL,
NULL,
init_record,
NULL,
read_stringin,
NULL};
epicsExportAddress(dset,devSiSoftCallback);
typedef struct notifyInfo {
processNotify *ppn;
CALLBACK *pcallback;
char value[40];
int status;
}notifyInfo;
static void getCallback(processNotify *ppn,notifyGetType type)
{
struct stringinRecord *pstringin = (struct stringinRecord *)ppn->usrPvt;
notifyInfo *pnotifyInfo = (notifyInfo *)pstringin->dpvt;
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 = dbGetField(ppn->paddr,DBR_STRING,&pnotifyInfo->value,
&options,&no_elements,0);
break;
case getType:
status = dbGet(ppn->paddr,DBR_STRING,&pnotifyInfo->value,
&options,&no_elements,0);
break;
}
pnotifyInfo->status = status;
}
static void doneCallback(processNotify *ppn)
{
struct stringinRecord *pstringin = (struct stringinRecord *)ppn->usrPvt;
notifyInfo *pnotifyInfo = (notifyInfo *)pstringin->dpvt;
callbackRequestProcessCallback(pnotifyInfo->pcallback,pstringin->prio,pstringin);
}
static long init_record(struct stringinRecord *pstringin)
{
DBLINK *plink = &pstringin->inp;
struct instio *pinstio;
char *pvname;
DBADDR *pdbaddr=NULL;
long status;
notifyInfo *pnotifyInfo;
CALLBACK *pcallback;
processNotify *ppn=NULL;
if(plink->type!=INST_IO) {
recGblRecordError(S_db_badField,(void *)pstringin,
"devSiSoftCallback (init_record) linked record not found");
pstringin->pact=TRUE;
return(S_db_badField);
}
pinstio=(struct instio*)&(plink->value);
pvname = pinstio->string;
pdbaddr = callocMustSucceed(1, sizeof(*pdbaddr),
"devSiSoftCallback::init_record");
status = dbNameToAddr(pvname,pdbaddr);
if(status) {
recGblRecordError(status,(void *)pstringin,
"devSiSoftCallback (init_record) Illegal INP field");
pstringin->pact=TRUE;
return(status);
}
pnotifyInfo = callocMustSucceed(1, sizeof(*pnotifyInfo),
"devSiSoftCallback::init_record");
pcallback = callocMustSucceed(1, sizeof(*pcallback),
"devSiSoftCallback::init_record");
ppn = callocMustSucceed(1, sizeof(*ppn),
"devSiSoftCallback::init_record");
pnotifyInfo->ppn = ppn;
pnotifyInfo->pcallback = pcallback;
ppn->usrPvt = pstringin;
ppn->paddr = pdbaddr;
ppn->getCallback = getCallback;
ppn->doneCallback = doneCallback;
ppn->requestType = processGetRequest;
pstringin->dpvt = pnotifyInfo;
return 0;
}
static long read_stringin(stringinRecord *pstringin)
{
notifyInfo *pnotifyInfo = (notifyInfo *)pstringin->dpvt;
if(pstringin->pact) {
if(pnotifyInfo->status) {
recGblSetSevr(pstringin,READ_ALARM,INVALID_ALARM);
return(pnotifyInfo->status);
}
strcpy(pstringin->val,pnotifyInfo->value);
pstringin->udf = FALSE;
return(0);
}
dbProcessNotify(pnotifyInfo->ppn);
pstringin->pact = TRUE;
return(0);
}
+6
View File
@@ -27,6 +27,12 @@ device(mbbiDirect,CONSTANT,devMbbiDirectSoftRaw,"Raw Soft Channel")
device(mbbo,CONSTANT,devMbboSoftRaw,"Raw Soft Channel")
device(mbboDirect,CONSTANT,devMbboDirectSoftRaw,"Raw Soft Channel")
device(ai,INST_IO,devAiSoftCallback,"Async Soft Channel")
device(bi,INST_IO,devBiSoftCallback,"Async Soft Channel")
device(mbbi,INST_IO,devMbbiSoftCallback,"Async Soft Channel")
device(longin,INST_IO,devLiSoftCallback,"Async Soft Channel")
device(stringin,INST_IO,devSiSoftCallback,"Async Soft Channel")
device(ao,CONSTANT,devAoSoftCallback,"Async Soft Channel")
device(bo,CONSTANT,devBoSoftCallback,"Async Soft Channel")
device(calcout,CONSTANT,devCalcoutSoftCallback,"Async Soft Channel")