Marty Kraimer's changes to support process-get operations.
This commit is contained in:
+2
-1
@@ -55,7 +55,8 @@
|
||||
#include "db_convert.h"
|
||||
#include "resourceLib.h"
|
||||
|
||||
extern "C" void putNotifyCompletion ( putNotify *ppn );
|
||||
extern "C" int putNotifyPut ( processNotify *ppn, notifyPutType notifyPutType );
|
||||
extern "C" void putNotifyCompletion ( processNotify *ppn );
|
||||
|
||||
class dbContext;
|
||||
class dbChannelIO;
|
||||
|
||||
@@ -171,16 +171,16 @@
|
||||
extra("struct asgMember *asp")
|
||||
}
|
||||
field(PPN,DBF_NOACCESS) {
|
||||
prompt("addr of PUTNOTIFY")
|
||||
prompt("pprocessNotify")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("struct putNotify *ppn")
|
||||
extra("struct processNotify *ppn")
|
||||
}
|
||||
field(PPNR,DBF_NOACCESS) {
|
||||
prompt("pputNotifyRecord")
|
||||
prompt("pprocessNotifyRecord")
|
||||
special(SPC_NOMOD)
|
||||
interest(4)
|
||||
extra("struct putNotifyRecord *ppnr")
|
||||
extra("struct processNotifyRecord *ppnr")
|
||||
}
|
||||
field(SPVT,DBF_NOACCESS) {
|
||||
prompt("Scan Private")
|
||||
|
||||
+307
-227
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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),
|
||||
|
||||
@@ -140,7 +140,7 @@ int iocBuild(void)
|
||||
errlogPrintf("iocBuild: asInit Failed.\n");
|
||||
return -1;
|
||||
}
|
||||
dbPutNotifyInit();
|
||||
dbProcessNotifyInit();
|
||||
epicsThreadSleep(.5);
|
||||
initHookAnnounce(initHookAfterScanInit);
|
||||
|
||||
|
||||
+51
-26
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user