diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 14258f352..43d2a9d62 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -18,9 +18,14 @@
Dynamic array sizing support was added to the IOC server (RSRV) in the
Base-3.14.12 release, but has not until now been supported in the Portable
Channel Access Server
(PCAS). Channel Access server applications using the
-PCAS will have to be modified slightly to provide full support for variable
-length arrays, but unmodified applications will continue to build and work as
-before against this release.
+PCAS may not need to be modified at all; if they already push monitors with
+different gdd array lengths, those variable sizes will be forwarded to any CA
+clients who have requested variable length updates. The example CAS server
+application has been modified to demonstrate this feature.
+
+In implementing the above, the gdd method gdd::put(const gdd *) now
+copies the full-sized array from the source gdd if the destination gdd is of
+type array, has no allocated memory and a boundary size of 0.
Additional epicsTime conversion
diff --git a/src/cas/generic/caServerI.h b/src/cas/generic/caServerI.h
index 6037d8c20..b45d9373a 100644
--- a/src/cas/generic/caServerI.h
+++ b/src/cas/generic/caServerI.h
@@ -40,8 +40,13 @@ class casIntfOS;
class casMonitor;
class casChannelI;
-caStatus convertContainerMemberToAtomic ( class gdd & dd,
- aitUint32 appType, aitUint32 elemCount );
+caStatus convertContainerMemberToAtomic (class gdd & dd,
+ aitUint32 appType, aitUint32 requestedCount, aitUint32 nativeCount);
+
+// Keep the old signature for backward compatibility
+inline caStatus convertContainerMemberToAtomic (class gdd & dd,
+ aitUint32 appType, aitUint32 elemCount)
+{ return convertContainerMemberToAtomic(dd, appType, elemCount, elemCount); }
class caServerI :
public caServerIO,
diff --git a/src/cas/generic/casStrmClient.cc b/src/cas/generic/casStrmClient.cc
index bf83a7f45..6cfab04dd 100644
--- a/src/cas/generic/casStrmClient.cc
+++ b/src/cas/generic/casStrmClient.cc
@@ -409,17 +409,8 @@ caStatus casStrmClient::verifyRequest (casChannelI * & pChan , bool allowdyn)
//
// element count out of range ?
//
- if ( allowdyn && ctx.msg.m_count==0 &&
- CA_V413 ( this->minor_version_number ) ) {
- // Hack
- // Since GDD interface doesn't support variable sized arrays
- // we present dynamic requests as max size.
- // This allows PCAS to claim support for dynamic arrays w/o
- // going to the trouble of fixing GDD.
- ctx.msg.m_count = pChan->getPVI().nativeCount();
- }
- else if ( ctx.msg.m_count > pChan->getPVI().nativeCount() ||
- ctx.msg.m_count == 0u ) {
+ if ( ctx.msg.m_count > pChan->getPVI().nativeCount() ||
+ ( !allowdyn && ctx.msg.m_count == 0u ) ) {
return ECA_BADCOUNT;
}
@@ -452,7 +443,7 @@ caStatus casStrmClient::readAction ( epicsGuard < casClientMutex > & guard )
casChannelI * pChan;
{
- caStatus status = this->verifyRequest ( pChan, true );
+ caStatus status = this->verifyRequest ( pChan, CA_V413 ( this->minor_version_number ) );
if ( status != ECA_NORMAL ) {
if ( pChan ) {
return this->sendErr ( guard, mp, pChan->getCID(),
@@ -539,11 +530,15 @@ caStatus casStrmClient::readResponse ( epicsGuard < casClientMutex > & guard,
pChan->getCID(), status, ECA_GETFAIL );
}
+ ca_uint32_t count = (msg.m_count == 0) ?
+ (ca_uint32_t)desc.getDataSizeElements() :
+ msg.m_count;
+
void * pPayload;
{
- unsigned payloadSize = dbr_size_n ( msg.m_dataType, msg.m_count );
+ unsigned payloadSize = dbr_size_n ( msg.m_dataType, count );
caStatus localStatus = this->out.copyInHeader ( msg.m_cmmd, payloadSize,
- msg.m_dataType, msg.m_count, pChan->getCID (),
+ msg.m_dataType, count, pChan->getCID (),
msg.m_available, & pPayload );
if ( localStatus ) {
if ( localStatus==S_cas_hugeRequest ) {
@@ -559,21 +554,21 @@ caStatus casStrmClient::readResponse ( epicsGuard < casClientMutex > & guard,
// (places the data in network format)
//
int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr(
- pPayload, msg.m_count, desc, pChan->enumStringTable() );
+ pPayload, count, desc, pChan->enumStringTable() );
if ( mapDBRStatus < 0 ) {
desc.dump ();
errPrintf ( S_cas_badBounds, __FILE__, __LINE__, "- get with PV=%s type=%u count=%u",
- pChan->getPVI().getName(), msg.m_dataType, msg.m_count );
+ pChan->getPVI().getName(), msg.m_dataType, count );
return this->sendErrWithEpicsStatus (
guard, & msg, pChan->getCID(), S_cas_badBounds, ECA_GETFAIL );
}
int cacStatus = caNetConvert (
- msg.m_dataType, pPayload, pPayload, true, msg.m_count );
+ msg.m_dataType, pPayload, pPayload, true, count );
if ( cacStatus != ECA_NORMAL ) {
return this->sendErrWithEpicsStatus (
guard, & msg, pChan->getCID(), S_cas_internal, cacStatus );
}
- if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) {
+ if ( msg.m_dataType == DBR_STRING && count == 1u ) {
unsigned reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u;
this->out.commitMsg ( reducedPayloadSize );
}
@@ -593,7 +588,7 @@ caStatus casStrmClient::readNotifyAction ( epicsGuard < casClientMutex > & guard
casChannelI * pChan;
{
- caStatus status = this->verifyRequest ( pChan, true );
+ caStatus status = this->verifyRequest ( pChan, CA_V413 ( this->minor_version_number ) );
if ( status != ECA_NORMAL ) {
return this->readNotifyFailureResponse ( guard, * mp, status );
}
@@ -664,11 +659,15 @@ caStatus casStrmClient::readNotifyResponse ( epicsGuard < casClientMutex > & gua
return ecaStatus;
}
+ ca_uint32_t count = (msg.m_count == 0) ?
+ (ca_uint32_t)desc.getDataSizeElements() :
+ msg.m_count;
+
void *pPayload;
{
- unsigned size = dbr_size_n ( msg.m_dataType, msg.m_count );
+ unsigned size = dbr_size_n ( msg.m_dataType, count );
caStatus status = this->out.copyInHeader ( msg.m_cmmd, size,
- msg.m_dataType, msg.m_count, ECA_NORMAL,
+ msg.m_dataType, count, ECA_NORMAL,
msg.m_available, & pPayload );
if ( status ) {
if ( status == S_cas_hugeRequest ) {
@@ -683,23 +682,23 @@ caStatus casStrmClient::readNotifyResponse ( epicsGuard < casClientMutex > & gua
// convert gdd to db_access type
//
int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr ( pPayload,
- msg.m_count, desc, pChan->enumStringTable() );
+ count, desc, pChan->enumStringTable() );
if ( mapDBRStatus < 0 ) {
desc.dump();
errPrintf ( S_cas_badBounds, __FILE__, __LINE__,
"- get notify with PV=%s type=%u count=%u",
- pChan->getPVI().getName(), msg.m_dataType, msg.m_count );
+ pChan->getPVI().getName(), msg.m_dataType, count );
return this->readNotifyFailureResponse ( guard, msg, ECA_NOCONVERT );
}
int cacStatus = caNetConvert (
- msg.m_dataType, pPayload, pPayload, true, msg.m_count );
+ msg.m_dataType, pPayload, pPayload, true, count );
if ( cacStatus != ECA_NORMAL ) {
return this->sendErrWithEpicsStatus (
guard, & msg, pChan->getCID(), S_cas_internal, cacStatus );
}
- if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) {
+ if ( msg.m_dataType == DBR_STRING && count == 1u ) {
unsigned reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u;
this->out.commitMsg ( reducedPayloadSize );
}
@@ -735,8 +734,8 @@ caStatus casStrmClient::readNotifyFailureResponse (
// to be more efficent if it discovers that the source has less data
// than the destination)
//
-caStatus convertContainerMemberToAtomic ( gdd & dd,
- aitUint32 appType, aitUint32 elemCount )
+caStatus convertContainerMemberToAtomic ( gdd & dd,
+ aitUint32 appType, aitUint32 requestedCount, aitUint32 nativeCount )
{
gdd * pVal;
if ( dd.isContainer() ) {
@@ -763,13 +762,13 @@ caStatus convertContainerMemberToAtomic ( gdd & dd,
return S_cas_badType;
}
- if ( elemCount <= 1 ) {
+ if ( nativeCount <= 1 ) {
return S_cas_success;
}
// convert to atomic
gddBounds bds;
- bds.setSize ( elemCount );
+ bds.setSize ( requestedCount );
bds.setFirst ( 0u );
pVal->setDimension ( 1u, & bds );
return S_cas_success;
@@ -778,9 +777,9 @@ caStatus convertContainerMemberToAtomic ( gdd & dd,
//
// createDBRDD ()
//
-static caStatus createDBRDD ( unsigned dbrType,
- unsigned elemCount, gdd * & pDD )
-{
+static caStatus createDBRDD ( unsigned dbrType,
+ unsigned requestedCount, unsigned nativeCount, gdd * & pDD )
+{
/*
* DBR type has already been checked, but it is possible
* that "gddDbrToAit" will not track with changes in
@@ -807,7 +806,7 @@ static caStatus createDBRDD ( unsigned dbrType,
// fix the value element count
caStatus status = convertContainerMemberToAtomic (
- *pDescRet, gddAppType_value, elemCount );
+ *pDescRet, gddAppType_value, requestedCount, nativeCount );
if ( status != S_cas_success ) {
pDescRet->unreference ();
return status;
@@ -857,11 +856,15 @@ caStatus casStrmClient::monitorResponse (
casChannelI & chan, const caHdrLargeArray & msg,
const gdd & desc, const caStatus completionStatus )
{
+ ca_uint32_t count = (msg.m_count == 0) ?
+ (ca_uint32_t)desc.getDataSizeElements() :
+ msg.m_count;
+
void * pPayload = 0;
{
- ca_uint32_t size = dbr_size_n ( msg.m_dataType, msg.m_count );
+ ca_uint32_t size = dbr_size_n ( msg.m_dataType, count );
caStatus status = out.copyInHeader ( msg.m_cmmd, size,
- msg.m_dataType, msg.m_count, ECA_NORMAL,
+ msg.m_dataType, count, ECA_NORMAL,
msg.m_available, & pPayload );
if ( status ) {
if ( status == S_cas_hugeRequest ) {
@@ -879,7 +882,8 @@ caStatus casStrmClient::monitorResponse (
gdd * pDBRDD = 0;
if ( completionStatus == S_cas_success ) {
- caStatus status = createDBRDD ( msg.m_dataType, msg.m_count, pDBRDD );
+ caStatus status = createDBRDD ( msg.m_dataType, count,
+ chan.getPVI().nativeCount(), pDBRDD );
if ( status != S_cas_success ) {
caStatus ecaStatus;
if ( status == S_cas_badType ) {
@@ -900,7 +904,7 @@ caStatus casStrmClient::monitorResponse (
pDBRDD->unreference ();
errPrintf ( S_cas_noConvert, __FILE__, __LINE__,
"no conversion between event app type=%d and DBR type=%d Element count=%d",
- desc.applicationType (), msg.m_dataType, msg.m_count);
+ desc.applicationType (), msg.m_dataType, count);
return monitorFailureResponse ( guard, msg, ECA_NOCONVERT );
}
}
@@ -923,14 +927,14 @@ caStatus casStrmClient::monitorResponse (
}
int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr (
- pPayload, msg.m_count, *pDBRDD, chan.enumStringTable() );
+ pPayload, count, *pDBRDD, chan.enumStringTable() );
if ( mapDBRStatus < 0 ) {
pDBRDD->unreference ();
return monitorFailureResponse ( guard, msg, ECA_NOCONVERT );
}
int cacStatus = caNetConvert (
- msg.m_dataType, pPayload, pPayload, true, msg.m_count );
+ msg.m_dataType, pPayload, pPayload, true, count );
if ( cacStatus != ECA_NORMAL ) {
pDBRDD->unreference ();
return this->sendErrWithEpicsStatus (
@@ -940,7 +944,7 @@ caStatus casStrmClient::monitorResponse (
//
// force string message size to be the true size
//
- if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) {
+ if ( msg.m_dataType == DBR_STRING && count == 1u ) {
ca_uint32_t reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u;
this->out.commitMsg ( reducedPayloadSize );
}
@@ -1948,7 +1952,7 @@ caStatus casStrmClient::eventAddAction (
casChannelI *pciu;
{
- caStatus status = casStrmClient::verifyRequest ( pciu, true );
+ caStatus status = casStrmClient::verifyRequest ( pciu, CA_V413 ( this->minor_version_number ) );
if ( status != ECA_NORMAL ) {
if ( pciu ) {
return this->sendErr ( guard, mp,
@@ -2609,8 +2613,8 @@ caStatus casStrmClient::read ()
{
gdd * pDD = 0;
- caStatus status = createDBRDD ( pHdr->m_dataType,
- pHdr->m_count, pDD );
+ caStatus status = createDBRDD ( pHdr->m_dataType, pHdr->m_count,
+ this->ctx.getChannel()->getPVI().nativeCount(), pDD );
if ( status != S_cas_success ) {
return status;
}
diff --git a/src/gdd/gdd.cc b/src/gdd/gdd.cc
index 1a84808c6..162236b55 100644
--- a/src/gdd/gdd.cc
+++ b/src/gdd/gdd.cc
@@ -1355,8 +1355,9 @@ gddStatus gdd::put ( const gdd * dd )
}
aitUint32 srcAvailSize = srcElemCount - unusedSrcBelow;
- if ( srcAvailSize > this->getBounds()->size() ) {
- srcCopySize = this->getBounds()->size();
+ aitUint32 destSize = this->getBounds()->size();
+ if ( destSize > 0 && srcAvailSize > destSize ) {
+ srcCopySize = destSize;
}
else {
srcCopySize = srcAvailSize;
diff --git a/src/makeBaseApp/top/caServerApp/exAsyncPV.cc b/src/makeBaseApp/top/caServerApp/exAsyncPV.cc
index 7e0758c13..b5bff9181 100644
--- a/src/makeBaseApp/top/caServerApp/exAsyncPV.cc
+++ b/src/makeBaseApp/top/caServerApp/exAsyncPV.cc
@@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
@@ -30,23 +29,23 @@ exAsyncPV::exAsyncPV ( exServer & cas, pvInfo & setup,
//
caStatus exAsyncPV::read (const casCtx &ctx, gdd &valueIn)
{
- exAsyncReadIO *pIO;
-
- if ( this->simultAsychReadIOCount >= this->cas.maxSimultAsyncIO () ) {
- return S_casApp_postponeAsyncIO;
- }
+ exAsyncReadIO *pIO;
- pIO = new exAsyncReadIO ( this->cas, ctx,
- *this, valueIn, this->asyncDelay );
- if ( ! pIO ) {
+ if ( this->simultAsychReadIOCount >= this->cas.maxSimultAsyncIO () ) {
+ return S_casApp_postponeAsyncIO;
+ }
+
+ pIO = new exAsyncReadIO ( this->cas, ctx,
+ *this, valueIn, this->asyncDelay );
+ if ( ! pIO ) {
if ( this->simultAsychReadIOCount > 0 ) {
return S_casApp_postponeAsyncIO;
}
else {
- return S_casApp_noMemory;
+ return S_casApp_noMemory;
}
- }
- this->simultAsychReadIOCount++;
+ }
+ this->simultAsychReadIOCount++;
return S_casApp_asyncCompletion;
}
@@ -54,24 +53,24 @@ caStatus exAsyncPV::read (const casCtx &ctx, gdd &valueIn)
// exAsyncPV::writeNotify()
//
caStatus exAsyncPV::writeNotify ( const casCtx &ctx, const gdd &valueIn )
-{
- if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
- return S_casApp_postponeAsyncIO;
- }
+{
+ if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
+ return S_casApp_postponeAsyncIO;
+ }
- exAsyncWriteIO * pIO = new
+ exAsyncWriteIO * pIO = new
exAsyncWriteIO ( this->cas, ctx, *this,
- valueIn, this->asyncDelay );
- if ( ! pIO ) {
+ valueIn, this->asyncDelay );
+ if ( ! pIO ) {
if ( this->simultAsychReadIOCount > 0 ) {
return S_casApp_postponeAsyncIO;
}
else {
- return S_casApp_noMemory;
+ return S_casApp_noMemory;
}
}
- this->simultAsychWriteIOCount++;
- return S_casApp_asyncCompletion;
+ this->simultAsychWriteIOCount++;
+ return S_casApp_asyncCompletion;
}
//
@@ -79,24 +78,24 @@ caStatus exAsyncPV::writeNotify ( const casCtx &ctx, const gdd &valueIn )
//
caStatus exAsyncPV::write ( const casCtx &ctx, const gdd &valueIn )
{
- // implement the discard intermediate values, but last value
+ // implement the discard intermediate values, but last value
// sent always applied behavior that IOCs provide excepting
// that we will alow N requests to pend instead of a limit
// of only one imposed in the IOC
- if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
+ if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
pStandbyValue.set ( & valueIn );
- return S_casApp_success;
- }
-
- exAsyncWriteIO * pIO = new
- exAsyncWriteIO ( this->cas, ctx, *this,
- valueIn, this->asyncDelay );
- if ( ! pIO ) {
- pStandbyValue.set ( & valueIn );
- return S_casApp_success;
+ return S_casApp_success;
}
- this->simultAsychWriteIOCount++;
- return S_casApp_asyncCompletion;
+
+ exAsyncWriteIO * pIO = new
+ exAsyncWriteIO ( this->cas, ctx, *this,
+ valueIn, this->asyncDelay );
+ if ( ! pIO ) {
+ pStandbyValue.set ( & valueIn );
+ return S_casApp_success;
+ }
+ this->simultAsychWriteIOCount++;
+ return S_casApp_asyncCompletion;
}
// Implementing a specialized update for exAsyncPV
@@ -150,7 +149,7 @@ void exAsyncPV::removeWriteIO ()
exAsyncWriteIO::exAsyncWriteIO ( exServer & cas,
const casCtx & ctxIn, exAsyncPV & pvIn,
const gdd & valueIn, double asyncDelay ) :
- casAsyncWriteIO ( ctxIn ), pv ( pvIn ),
+ casAsyncWriteIO ( ctxIn ), pv ( pvIn ),
timer ( cas.createTimer () ), pValue(valueIn)
{
this->timer.start ( *this, asyncDelay );
@@ -168,7 +167,7 @@ exAsyncWriteIO::~exAsyncWriteIO()
if ( this->pValue.valid () ) {
this->pv.updateFromAsyncWrite ( *this->pValue );
}
- this->pv.removeWriteIO();
+ this->pv.removeWriteIO();
}
//
@@ -179,9 +178,9 @@ epicsTimerNotify::expireStatus exAsyncWriteIO::
expire ( const epicsTime & /* currentTime */ )
{
assert ( this->pValue.valid () );
- caStatus status = this->pv.updateFromAsyncWrite ( *this->pValue );
- this->pValue.set ( 0 );
- this->postIOCompletion ( status );
+ caStatus status = this->pv.updateFromAsyncWrite ( *this->pValue );
+ this->pValue.set ( 0 );
+ this->postIOCompletion ( status );
return noRestart;
}
@@ -191,7 +190,7 @@ epicsTimerNotify::expireStatus exAsyncWriteIO::
exAsyncReadIO::exAsyncReadIO ( exServer & cas, const casCtx & ctxIn,
exAsyncPV & pvIn, gdd & protoIn,
double asyncDelay ) :
- casAsyncReadIO ( ctxIn ), pv ( pvIn ),
+ casAsyncReadIO ( ctxIn ), pv ( pvIn ),
timer ( cas.createTimer() ), pProto ( protoIn )
{
this->timer.start ( *this, asyncDelay );
@@ -202,7 +201,7 @@ exAsyncReadIO::exAsyncReadIO ( exServer & cas, const casCtx & ctxIn,
//
exAsyncReadIO::~exAsyncReadIO()
{
- this->pv.removeReadIO ();
+ this->pv.removeReadIO ();
this->timer.destroy ();
}
@@ -213,16 +212,16 @@ exAsyncReadIO::~exAsyncReadIO()
epicsTimerNotify::expireStatus
exAsyncReadIO::expire ( const epicsTime & /* currentTime */ )
{
- //
- // map between the prototype in and the
- // current value
- //
- caStatus status = this->pv.exPV::readNoCtx ( this->pProto );
+ //
+ // map between the prototype in and the
+ // current value
+ //
+ caStatus status = this->pv.exPV::readNoCtx ( this->pProto );
- //
- // post IO completion
- //
- this->postIOCompletion ( status, *this->pProto );
+ //
+ // post IO completion
+ //
+ this->postIOCompletion ( status, *this->pProto );
return noRestart;
}
diff --git a/src/makeBaseApp/top/caServerApp/exPV.cc b/src/makeBaseApp/top/caServerApp/exPV.cc
index bc88b15bb..c21079cd4 100644
--- a/src/makeBaseApp/top/caServerApp/exPV.cc
+++ b/src/makeBaseApp/top/caServerApp/exPV.cc
@@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// Example EPICS CA server
@@ -42,7 +41,7 @@ exPV::exPV ( exServer & casIn, pvInfo & setup,
//
// no dataless PV allowed
//
- assert (this->info.getElementCount()>=1u);
+ assert (this->info.getCapacity()>=1u);
//
// start a very slow background scan
diff --git a/src/makeBaseApp/top/caServerApp/exServer.cc b/src/makeBaseApp/top/caServerApp/exServer.cc
index cff290838..b02c0b9a5 100644
--- a/src/makeBaseApp/top/caServerApp/exServer.cc
+++ b/src/makeBaseApp/top/caServerApp/exServer.cc
@@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// fileDescriptorManager.process(delay);
@@ -304,7 +303,7 @@ exPV *pvInfo::createPV ( exServer & cas, bool preCreateFlag,
// depending on the io type and the number
// of elements
//
- if (this->elementCount==1u) {
+ if (this->capacity==1u) {
switch (this->ioType){
case excasIoSync:
pNewPV = new exScalarPV ( cas, *this, preCreateFlag, scanOn );
diff --git a/src/makeBaseApp/top/caServerApp/exServer.h b/src/makeBaseApp/top/caServerApp/exServer.h
index 5fb6adaf7..819e1a30e 100644
--- a/src/makeBaseApp/top/caServerApp/exServer.h
+++ b/src/makeBaseApp/top/caServerApp/exServer.h
@@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// Example EPICS CA server
@@ -76,8 +75,10 @@ public:
double getLopr () const;
aitEnum getType () const;
excasIoType getIOType () const;
- unsigned getElementCount () const;
- void unlinkPV ();
+ unsigned getCapacity () const;
+ unsigned getElementCount () const;
+ void setElementCount (unsigned);
+ void unlinkPV ();
exPV *createPV ( exServer & exCAS, bool preCreateFlag,
bool scanOn, double asyncDelay );
void deletePV ();
@@ -88,7 +89,8 @@ private:
const double lopr;
aitEnum type;
const excasIoType ioType;
- const unsigned elementCount;
+ const unsigned capacity;
+ unsigned elementCount;
exPV * pPV;
pvInfo & operator = ( const pvInfo & );
};
@@ -441,8 +443,8 @@ inline pvInfo::pvInfo ( double scanPeriodIn, const char *pNameIn,
scanPeriod ( scanPeriodIn ), pName ( pNameIn ),
hopr ( hoprIn ), lopr ( loprIn ), type ( typeIn ),
- ioType ( ioTypeIn ), elementCount ( countIn ),
- pPV ( 0 )
+ ioType ( ioTypeIn ), capacity ( countIn ),
+ elementCount ( 0 ), pPV ( 0 )
{
}
@@ -454,8 +456,8 @@ inline pvInfo::pvInfo ( const pvInfo & copyIn ) :
scanPeriod ( copyIn.scanPeriod ), pName ( copyIn.pName ),
hopr ( copyIn.hopr ), lopr ( copyIn.lopr ), type ( copyIn.type ),
- ioType ( copyIn.ioType ), elementCount ( copyIn.elementCount ),
- pPV ( copyIn.pPV )
+ ioType ( copyIn.ioType ), capacity ( copyIn.capacity ),
+ elementCount ( copyIn.elementCount ), pPV ( copyIn.pPV )
{
}
@@ -509,12 +511,22 @@ inline excasIoType pvInfo::getIOType () const
return this->ioType;
}
-inline unsigned pvInfo::getElementCount () const
-{
- return this->elementCount;
+inline unsigned pvInfo::getCapacity () const
+{
+ return this->capacity;
}
-inline void pvInfo::unlinkPV ()
+inline unsigned pvInfo::getElementCount () const
+{
+ return this->elementCount;
+}
+
+inline void pvInfo::setElementCount (unsigned newCount)
+{
+ this->elementCount = newCount;
+}
+
+inline void pvInfo::unlinkPV ()
{
this->pPV = NULL;
}
diff --git a/src/makeBaseApp/top/caServerApp/exVectorPV.cc b/src/makeBaseApp/top/caServerApp/exVectorPV.cc
index da357831f..e60e96682 100644
--- a/src/makeBaseApp/top/caServerApp/exVectorPV.cc
+++ b/src/makeBaseApp/top/caServerApp/exVectorPV.cc
@@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
-* EPICS BASE Versions 3.13.7
-* and higher are distributed subject to a Software License Agreement found
-* in file LICENSE that is included with this distribution.
+* EPICS BASE is distributed subject to a Software License Agreement found
+* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include "exServer.h"
@@ -48,7 +47,7 @@ unsigned exVectorPV::maxDimension() const
aitIndex exVectorPV::maxBound (unsigned dimension) const // X aCC 361
{
if (dimension==0u) {
- return this->info.getElementCount();
+ return this->info.getCapacity();
}
else {
return 0u;
@@ -60,26 +59,21 @@ aitIndex exVectorPV::maxBound (unsigned dimension) const // X aCC 361
//
void exVectorPV::scan()
{
- caStatus status;
- double radians;
- smartGDDPointer pDD;
- aitFloat32 *pF, *pFE;
- const aitFloat32 *pCF;
- float newValue;
- float limit;
- exVecDestructor *pDest;
- int gddStatus;
+ static epicsTime startTime = epicsTime::getCurrent();
- //
- // update current time (so we are not required to do
- // this every time that we write the PV which impacts
- // throughput under sunos4 because gettimeofday() is
- // slow)
+ // update current time
//
this->currentTime = epicsTime::getCurrent();
-
- pDD = new gddAtomic (gddAppType_value, aitEnumFloat64,
- 1u, this->info.getElementCount());
+
+ // demonstrate a changing array size
+ unsigned ramp = 15 & (unsigned) (this->currentTime - startTime);
+ unsigned newSize = this->info.getCapacity();
+ if (newSize > ramp) {
+ newSize -= ramp;
+ }
+
+ smartGDDPointer pDD = new gddAtomic (gddAppType_value, aitEnumFloat64,
+ 1u, newSize);
if ( ! pDD.valid () ) {
return;
}
@@ -87,18 +81,18 @@ void exVectorPV::scan()
//
// smart pointer class manages reference count after this point
//
- gddStatus = pDD->unreference();
- assert (!gddStatus);
+ gddStatus gdds = pDD->unreference();
+ assert(!gdds);
//
// allocate array buffer
//
- pF = new aitFloat32 [this->info.getElementCount()];
+ aitFloat64 * pF = new aitFloat64 [newSize];
if (!pF) {
return;
}
- pDest = new exVecDestructor;
+ exVecDestructor * pDest = new exVecDestructor;
if (!pDest) {
delete [] pF;
return;
@@ -114,37 +108,39 @@ void exVectorPV::scan()
// double check for reasonable bounds on the
// current value
//
- pCF=NULL;
- if ( this->pValue.valid () ) {
- if (this->pValue->dimension()==1u) {
- const gddBounds *pB = this->pValue->getBounds();
- if (pB[0u].size()==this->info.getElementCount()) {
- pCF = *this->pValue;
- }
- }
+ const aitFloat64 *pCF = NULL, *pCFE = NULL;
+ if (this->pValue.valid () &&
+ this->pValue->dimension() == 1u) {
+ const gddBounds *pB = this->pValue->getBounds();
+
+ pCF = *this->pValue;
+ pCFE = &pCF[pB->size()];
}
- pFE = &pF[this->info.getElementCount()];
- while (pFinfo.getHopr();
+ newValue += (sin (radians) / 10.0);
+ double limit = this->info.getHopr();
newValue = tsMin (newValue, limit);
- limit = (float) this->info.getLopr();
+ limit = this->info.getLopr();
newValue = tsMax (newValue, limit);
- *(pF++) = newValue;
+ *pF++ = newValue;
}
aitTimeStamp gddts = this->currentTime;
pDD->setTimeStamp ( & gddts );
- status = this->update ( *pDD );
+ caStatus status = this->update ( *pDD );
+ this->info.setElementCount(newSize);
+
if ( status != S_casApp_success ) {
errMessage (status, "vector scan update failed\n");
}
@@ -166,7 +162,7 @@ void exVectorPV::scan()
//
caStatus exVectorPV::updateValue ( const gdd & value )
{
-
+ aitUint32 newSize = 0;
//
// Check bounds of incoming request
// (and see if we are replacing all elements -
@@ -183,7 +179,9 @@ caStatus exVectorPV::updateValue ( const gdd & value )
if ( pb[0u].first() != 0u ) {
return S_casApp_outOfBounds;
}
- else if ( pb[0u].size() > this->info.getElementCount() ) {
+
+ newSize = pb[0u].size();
+ if ( newSize > this->info.getCapacity() ) {
return S_casApp_outOfBounds;
}
}
@@ -193,14 +191,14 @@ caStatus exVectorPV::updateValue ( const gdd & value )
//
return S_casApp_outOfBounds;
}
-
+
//
// Create a new array data descriptor
// (so that old values that may be referenced on the
// event queue are not replaced)
//
- smartGDDPointer pNewValue ( new gddAtomic ( gddAppType_value, aitEnumFloat64,
- 1u, this->info.getElementCount() ) );
+ smartGDDPointer pNewValue ( new gddAtomic ( gddAppType_value, aitEnumFloat64,
+ 1u, newSize ) );
if ( ! pNewValue.valid() ) {
return S_casApp_noMemory;
}
@@ -211,21 +209,20 @@ caStatus exVectorPV::updateValue ( const gdd & value )
//
gddStatus gdds = pNewValue->unreference( );
assert ( ! gdds );
-
+
//
// allocate array buffer
//
- aitFloat64 * pF = new aitFloat64 [this->info.getElementCount()];
+ aitFloat64 * pF = new aitFloat64 [newSize];
if (!pF) {
return S_casApp_noMemory;
}
-
+
//
// Install (and initialize) array buffer
// if no old values exist
//
- unsigned count = this->info.getElementCount();
- for ( unsigned i = 0u; i < count; i++ ) {
+ for ( unsigned i = 0u; i < newSize; i++ ) {
pF[i] = 0.0f;
}
@@ -240,7 +237,7 @@ caStatus exVectorPV::updateValue ( const gdd & value )
// (do this before we increment pF)
//
pNewValue->putRef ( pF, pDest );
-
+
//
// copy in the values that they are writing
//
@@ -248,9 +245,10 @@ caStatus exVectorPV::updateValue ( const gdd & value )
if ( gdds ) {
return S_cas_noConvert;
}
-
+
this->pValue = pNewValue;
-
+ this->info.setElementCount(newSize);
+
return S_casApp_success;
}
@@ -261,6 +259,6 @@ caStatus exVectorPV::updateValue ( const gdd & value )
//
void exVecDestructor::run ( void *pUntyped )
{
- aitFloat32 * pf = reinterpret_cast < aitFloat32 * > ( pUntyped );
+ aitFloat64 * pf = reinterpret_cast < aitFloat64 * > ( pUntyped );
delete [] pf;
}