Merged Michael's dbcadynamic branch
This commit is contained in:
@@ -346,15 +346,15 @@ long dbCaGetLink(struct link *plink,short dbrType, void *pdest,
|
||||
assert(pca->pgetNative);
|
||||
status = fConvert(pca->pgetNative, pdest, 0);
|
||||
} else {
|
||||
long ntoget = *nelements;
|
||||
unsigned long ntoget = *nelements;
|
||||
struct dbAddr dbAddr;
|
||||
long (*aConvert)(struct dbAddr *paddr, void *to, long nreq, long nto, long off);
|
||||
|
||||
aConvert = dbGetConvertRoutine[newType][dbrType];
|
||||
assert(pca->pgetNative);
|
||||
|
||||
if (ntoget > pca->nelements)
|
||||
ntoget = pca->nelements;
|
||||
if (ntoget > pca->usedelements)
|
||||
ntoget = pca->usedelements;
|
||||
*nelements = ntoget;
|
||||
|
||||
memset((void *)&dbAddr, 0, sizeof(dbAddr));
|
||||
@@ -409,6 +409,7 @@ long dbCaPutLinkCallback(struct link *plink,short dbrType,
|
||||
if (!pca->pputNative) {
|
||||
pca->pputNative = dbCalloc(pca->nelements,
|
||||
dbr_value_size[ca_field_type(pca->chid)]);
|
||||
pca->putnelements = 0;
|
||||
/* Fixed and disabled by ANJ, see comment above.
|
||||
plink->value.pv_link.pvlMask |= pvlOptOutNative;
|
||||
*/
|
||||
@@ -418,6 +419,7 @@ long dbCaPutLinkCallback(struct link *plink,short dbrType,
|
||||
|
||||
fConvert = dbFastPutConvertRoutine[dbrType][newType];
|
||||
status = fConvert(pbuffer, pca->pputNative, 0);
|
||||
pca->putnelements = 1;
|
||||
} else {
|
||||
struct dbAddr dbAddr;
|
||||
long (*aConvert)(struct dbAddr *paddr, const void *from, long nreq, long nfrom, long off);
|
||||
@@ -430,10 +432,7 @@ long dbCaPutLinkCallback(struct link *plink,short dbrType,
|
||||
if(nRequest>pca->nelements)
|
||||
nRequest = pca->nelements;
|
||||
status = aConvert(&dbAddr, pbuffer, nRequest, pca->nelements, 0);
|
||||
if(nRequest<pca->nelements) {
|
||||
long elemsize = dbr_value_size[ca_field_type(pca->chid)];
|
||||
memset(nRequest*elemsize+(char*)pca->pputNative, 0, (pca->nelements-nRequest)*elemsize);
|
||||
}
|
||||
pca->putnelements = nRequest;
|
||||
}
|
||||
link_action |= CA_WRITE_NATIVE;
|
||||
pca->gotOutNative = TRUE;
|
||||
@@ -705,6 +704,7 @@ static void connectionCallback(struct connection_handler_args arg)
|
||||
}
|
||||
pca->gotFirstConnection = TRUE;
|
||||
pca->nelements = ca_element_count(arg.chid);
|
||||
pca->usedelements = 0;
|
||||
pca->dbrType = ca_field_type(arg.chid);
|
||||
if ((plink->value.pv_link.pvlMask & pvlOptInpNative) && !pca->pgetNative) {
|
||||
link_action |= CA_MONITOR_NATIVE;
|
||||
@@ -757,6 +757,7 @@ static void eventCallback(struct event_handler_args arg)
|
||||
goto done;
|
||||
}
|
||||
assert(arg.dbr);
|
||||
assert(arg.count<=pca->nelements);
|
||||
size = arg.count * dbr_value_size[arg.type];
|
||||
if (arg.type == DBR_TIME_STRING &&
|
||||
ca_field_type(pca->chid) == DBR_ENUM) {
|
||||
@@ -773,6 +774,7 @@ static void eventCallback(struct event_handler_args arg)
|
||||
case DBR_TIME_DOUBLE:
|
||||
assert(pca->pgetNative);
|
||||
memcpy(pca->pgetNative, dbr_value_ptr(arg.dbr, arg.type), size);
|
||||
pca->usedelements = arg.count;
|
||||
pca->gotInNative = TRUE;
|
||||
break;
|
||||
default:
|
||||
@@ -978,11 +980,11 @@ static void dbCaTask(void *arg)
|
||||
assert(pca->pputNative);
|
||||
if (pca->putType == CA_PUT) {
|
||||
status = ca_array_put(
|
||||
pca->dbrType, pca->nelements,
|
||||
pca->dbrType, pca->putnelements,
|
||||
pca->chid, pca->pputNative);
|
||||
} else if (pca->putType==CA_PUT_CALLBACK) {
|
||||
status = ca_array_put_callback(
|
||||
pca->dbrType, pca->nelements,
|
||||
pca->dbrType, pca->putnelements,
|
||||
pca->chid, pca->pputNative,
|
||||
putComplete, pca);
|
||||
} else {
|
||||
@@ -1032,15 +1034,15 @@ static void dbCaTask(void *arg)
|
||||
}
|
||||
}
|
||||
if (link_action & CA_MONITOR_NATIVE) {
|
||||
size_t element_size;
|
||||
|
||||
element_size = dbr_value_size[ca_field_type(pca->chid)];
|
||||
|
||||
epicsMutexMustLock(pca->lock);
|
||||
pca->pgetNative = dbCalloc(pca->nelements, element_size);
|
||||
pca->elementSize = dbr_value_size[ca_field_type(pca->chid)];
|
||||
pca->pgetNative = dbCalloc(pca->nelements, pca->elementSize);
|
||||
epicsMutexUnlock(pca->lock);
|
||||
|
||||
status = ca_add_array_event(
|
||||
dbf_type_to_DBR_TIME(ca_field_type(pca->chid)),
|
||||
ca_element_count(pca->chid),
|
||||
0, /* dynamic size */
|
||||
pca->chid, eventCallback, pca, 0.0, 0.0, 0.0, 0);
|
||||
if (status != ECA_NORMAL) {
|
||||
errlogPrintf("dbCaTask ca_add_array_event %s\n",
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
/* write type */
|
||||
#define CA_PUT 0x1
|
||||
#define CA_PUT_CALLBACK 0x2
|
||||
|
||||
|
||||
typedef struct caLink
|
||||
{
|
||||
ELLNODE node;
|
||||
@@ -51,7 +51,10 @@ typedef struct caLink
|
||||
epicsTimeStamp timeStamp;
|
||||
/* The following have values after connection*/
|
||||
short dbrType;
|
||||
long nelements;
|
||||
size_t elementSize; /* size of one element in pgetNative */
|
||||
unsigned long nelements; /* PVs max array size */
|
||||
unsigned long usedelements; /* currently used in pgetNative */
|
||||
unsigned long putnelements; /* currently used in pputNative */
|
||||
char hasReadAccess;
|
||||
char hasWriteAccess;
|
||||
char isConnected;
|
||||
|
||||
@@ -154,7 +154,8 @@ void dbContext::callStateNotify ( struct dbChannel * dbch,
|
||||
const struct db_field_log * pfl,
|
||||
cacStateNotify & notifyIn )
|
||||
{
|
||||
unsigned long size = dbr_size_n ( type, count );
|
||||
long realcount = (count==0)?dbChannelElements(dbch):count;
|
||||
unsigned long size = dbr_size_n ( type, realcount );
|
||||
|
||||
if ( type > INT_MAX ) {
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
@@ -181,8 +182,13 @@ void dbContext::callStateNotify ( struct dbChannel * dbch,
|
||||
this->stateNotifyCacheSize = size;
|
||||
}
|
||||
void *pvfl = (void *) pfl;
|
||||
int status = dbChannel_get ( dbch, static_cast <int> ( type ),
|
||||
this->pStateNotifyCache, static_cast <int> ( count ), pvfl );
|
||||
int status;
|
||||
if(count==0) /* fetch actual number of elements (dynamic array) */
|
||||
status = dbChannel_get_count( dbch, static_cast <int> ( type ),
|
||||
this->pStateNotifyCache, &realcount, pvfl );
|
||||
else /* fetch requested number of elements, truncated or zero padded */
|
||||
status = dbChannel_get( dbch, static_cast <int> ( type ),
|
||||
this->pStateNotifyCache, realcount, pvfl );
|
||||
if ( status ) {
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
notifyIn.exception ( guard, ECA_GETFAIL,
|
||||
@@ -190,7 +196,7 @@ void dbContext::callStateNotify ( struct dbChannel * dbch,
|
||||
}
|
||||
else {
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
notifyIn.current ( guard, type, count, this->pStateNotifyCache );
|
||||
notifyIn.current ( guard, type, realcount, this->pStateNotifyCache );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,27 +61,32 @@ void dbContextReadNotifyCache::callReadNotify (
|
||||
return;
|
||||
}
|
||||
|
||||
if ( dbChannelElements(dbch) < 0 ) {
|
||||
const long maxcount = dbChannelElements(dbch);
|
||||
|
||||
if ( maxcount < 0 ) {
|
||||
notify.exception ( guard, ECA_BADCOUNT,
|
||||
"database has negetive element count",
|
||||
type, count);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( count > static_cast < unsigned long > ( dbChannelElements(dbch) ) ) {
|
||||
} else if ( count > (unsigned long)maxcount ) {
|
||||
notify.exception ( guard, ECA_BADCOUNT,
|
||||
"element count out of range (high side)",
|
||||
type, count);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long size = dbr_size_n ( type, count );
|
||||
long realcount = (count==0)?maxcount:count;
|
||||
unsigned long size = dbr_size_n ( type, realcount );
|
||||
|
||||
privateAutoDestroyPtr ptr ( _allocator, size );
|
||||
int status;
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
status = dbChannel_get ( dbch, static_cast <int> ( type ),
|
||||
ptr.get (), static_cast <long> ( count ), 0 );
|
||||
if ( count==0 )
|
||||
status = dbChannel_get_count ( dbch, (int)type, ptr.get(), &realcount, 0);
|
||||
else
|
||||
status = dbChannel_get ( dbch, (int)type, ptr.get (), realcount, 0 );
|
||||
}
|
||||
if ( status ) {
|
||||
notify.exception ( guard, ECA_GETFAIL,
|
||||
@@ -90,7 +95,7 @@ void dbContextReadNotifyCache::callReadNotify (
|
||||
}
|
||||
else {
|
||||
notify.completion (
|
||||
guard, type, count, ptr.get () );
|
||||
guard, type, realcount, ptr.get () );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "epicsString.h"
|
||||
#include "dbUnitTest.h"
|
||||
#include "epicsThread.h"
|
||||
#include "cantProceed.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "iocInit.h"
|
||||
#include "dbBase.h"
|
||||
@@ -301,7 +302,7 @@ static void fillArrayDouble(double *buf, unsigned count, double first)
|
||||
|
||||
static void checkArray(const char *msg,
|
||||
epicsInt32 *buf, epicsInt32 first,
|
||||
unsigned used, unsigned total)
|
||||
unsigned used)
|
||||
{
|
||||
int match = 1;
|
||||
unsigned i;
|
||||
@@ -309,22 +310,17 @@ static void checkArray(const char *msg,
|
||||
|
||||
for(b=buf,x=first,i=0;i<used;i++,x++,b++)
|
||||
match &= (*b)==x;
|
||||
for(;i<total;i++,x++,b++)
|
||||
match &= (*b)==0;
|
||||
testOk(match, "%s", msg);
|
||||
if(!match) {
|
||||
for(b=buf,x=first,i=0;i<used;i++,x++,b++)
|
||||
if((*b)!=x)
|
||||
testDiag("%u %u != %u", i, (unsigned)*b, (unsigned)x);
|
||||
for(;i<total;i++,x++,b++)
|
||||
if((*b)!=0)
|
||||
testDiag("%u %u != %u", i, (unsigned)*b, (unsigned)x);
|
||||
}
|
||||
}
|
||||
|
||||
static void checkArrayDouble(const char *msg,
|
||||
double *buf, double first,
|
||||
unsigned used, unsigned total)
|
||||
unsigned used)
|
||||
{
|
||||
int match = 1;
|
||||
unsigned i;
|
||||
@@ -332,16 +328,11 @@ static void checkArrayDouble(const char *msg,
|
||||
|
||||
for(b=buf,x=first,i=0;i<used;i++,x++,b++)
|
||||
match &= (*b)==x;
|
||||
for(;i<total;i++,x++,b++)
|
||||
match &= (*b)==0;
|
||||
testOk(match, "%s", msg);
|
||||
if(!match) {
|
||||
for(b=buf,x=first,i=0;i<used;i++,x++,b++)
|
||||
if((*b)!=x)
|
||||
testDiag("%u %u != %u", i, (unsigned)*b, (unsigned)x);
|
||||
for(;i<total;i++,x++,b++)
|
||||
if((*b)!=0)
|
||||
testDiag("%u %u != %u", i, (unsigned)*b, (unsigned)x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,12 +353,13 @@ static void testArrayLink(unsigned nsrc, unsigned ntarg)
|
||||
char buf[100];
|
||||
arrRecord *psrc, *ptarg;
|
||||
DBLINK *psrclnk;
|
||||
epicsInt32 *bufsrc, *buftarg;
|
||||
epicsInt32 *bufsrc, *buftarg, *tmpbuf;
|
||||
long nReq;
|
||||
unsigned num;
|
||||
unsigned num_min, num_max;
|
||||
|
||||
testDiag("Link to a array numeric field");
|
||||
|
||||
/* source.INP = "target CA" */
|
||||
epicsSnprintf(buf, sizeof(buf), "TARGET=target CA,FTVL=LONG,SNELM=%u,TNELM=%u",
|
||||
nsrc, ntarg);
|
||||
testDiag("%s", buf);
|
||||
@@ -391,9 +383,15 @@ static void testArrayLink(unsigned nsrc, unsigned ntarg)
|
||||
bufsrc = psrc->bptr;
|
||||
buftarg= ptarg->bptr;
|
||||
|
||||
num=psrc->nelm;
|
||||
if(num>ptarg->nelm)
|
||||
num=ptarg->nelm;
|
||||
num_max=num_min=psrc->nelm;
|
||||
if(num_min>ptarg->nelm)
|
||||
num_min=ptarg->nelm;
|
||||
if(num_max<ptarg->nelm)
|
||||
num_max=ptarg->nelm;
|
||||
/* always request more than can possibly be filled */
|
||||
num_max += 2;
|
||||
|
||||
tmpbuf = callocMustSucceed(num_max, sizeof(*tmpbuf), "tmpbuf");
|
||||
|
||||
startWait(psrclnk);
|
||||
|
||||
@@ -406,11 +404,22 @@ static void testArrayLink(unsigned nsrc, unsigned ntarg)
|
||||
waitForUpdate(psrclnk);
|
||||
|
||||
dbScanLock((dbCommon*)psrc);
|
||||
testDiag("fetch source.INP into source.BPTR");
|
||||
nReq = psrc->nelm;
|
||||
if(dbGetLink(psrclnk, DBR_LONG, bufsrc, NULL, &nReq)==0) {
|
||||
testPass("dbGetLink");
|
||||
testOp("%ld",nReq,==,(long)num);
|
||||
checkArray("array update", bufsrc, 1, nReq, psrc->nelm);
|
||||
testOp("%ld",nReq,==,(long)num_min);
|
||||
checkArray("array update", bufsrc, 1, nReq);
|
||||
} else {
|
||||
testFail("dbGetLink");
|
||||
testSkip(2, "dbGetLink fails");
|
||||
}
|
||||
testDiag("fetch source.INP into temp buffer w/ larger capacity");
|
||||
nReq = num_max;
|
||||
if(dbGetLink(psrclnk, DBR_LONG, tmpbuf, NULL, &nReq)==0) {
|
||||
testPass("dbGetLink");
|
||||
testOp("%ld",nReq,==,(long)ntarg);
|
||||
checkArray("array update", tmpbuf, 1, nReq);
|
||||
} else {
|
||||
testFail("dbGetLink");
|
||||
testSkip(2, "dbGetLink fails");
|
||||
@@ -422,12 +431,8 @@ static void testArrayLink(unsigned nsrc, unsigned ntarg)
|
||||
putLink(psrclnk, DBR_LONG, bufsrc, psrc->nelm);
|
||||
|
||||
dbScanLock((dbCommon*)ptarg);
|
||||
/* CA links always write the full target array length */
|
||||
testOp("%ld",(long)ptarg->nord,==,(long)ptarg->nelm);
|
||||
/* However, if the source length is less, then the target
|
||||
* is zero filled
|
||||
*/
|
||||
checkArray("array update", buftarg, 2, num, ptarg->nelm);
|
||||
testOp("%ld",(long)ptarg->nord,==,(long)num_min);
|
||||
|
||||
dbScanUnlock((dbCommon*)ptarg);
|
||||
|
||||
/* write again to ensure that buffer is completely updated */
|
||||
@@ -436,14 +441,15 @@ static void testArrayLink(unsigned nsrc, unsigned ntarg)
|
||||
putLink(psrclnk, DBR_LONG, bufsrc, psrc->nelm);
|
||||
|
||||
dbScanLock((dbCommon*)ptarg);
|
||||
testOp("%ld",(long)ptarg->nord,==,(long)ptarg->nelm);
|
||||
checkArray("array update", buftarg, 3, num, ptarg->nelm);
|
||||
testOp("%ld",(long)ptarg->nord,==,(long)num_min);
|
||||
checkArray("array update", buftarg, 3, num_min);
|
||||
dbScanUnlock((dbCommon*)ptarg);
|
||||
|
||||
testIocShutdownOk();
|
||||
|
||||
testdbCleanup();
|
||||
|
||||
free(tmpbuf);
|
||||
/* records don't cleanup after themselves
|
||||
* so do here to silence valgrind
|
||||
*/
|
||||
@@ -522,7 +528,7 @@ static void testreTargetTypeChange(void)
|
||||
|
||||
dbScanLock((dbCommon*)psrc);
|
||||
testOp("%ld",(long)psrc->nord,==,(long)5);
|
||||
checkArrayDouble("array update", bufsrc, 1, 5, psrc->nelm);
|
||||
checkArrayDouble("array update", bufsrc, 1, 5);
|
||||
dbScanUnlock((dbCommon*)psrc);
|
||||
|
||||
testDiag("Retarget");
|
||||
@@ -532,7 +538,7 @@ static void testreTargetTypeChange(void)
|
||||
|
||||
dbScanLock((dbCommon*)psrc);
|
||||
testOp("%ld",(long)psrc->nord,==,(long)5);
|
||||
checkArrayDouble("array update", bufsrc, 2, 5, psrc->nelm);
|
||||
checkArrayDouble("array update", bufsrc, 2, 5);
|
||||
dbScanUnlock((dbCommon*)psrc);
|
||||
|
||||
testIocShutdownOk();
|
||||
@@ -592,7 +598,7 @@ static void testCAC(void)
|
||||
|
||||
MAIN(dbCaLinkTest)
|
||||
{
|
||||
testPlan(91);
|
||||
testPlan(99);
|
||||
testNativeLink();
|
||||
testStringLink();
|
||||
testCP();
|
||||
|
||||
Reference in New Issue
Block a user