Merged the pcas-vararray-3.14 branch, with fixes and notes
This commit is contained in:
@@ -18,9 +18,14 @@
|
||||
<p>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 <q>Portable
|
||||
Channel Access Server</q> (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.</p>
|
||||
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.</p>
|
||||
|
||||
<p>In implementing the above, the gdd method <tt>gdd::put(const gdd *)</tt> 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.</p>
|
||||
|
||||
<h3>Additional epicsTime conversion</h3>
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 (pF<pFE) {
|
||||
radians = (rand () * 2.0 * myPI)/RAND_MAX;
|
||||
if (pCF) {
|
||||
aitFloat64 * pFE = &pF[newSize];
|
||||
while (pF < pFE) {
|
||||
double radians = (rand () * 2.0 * myPI)/RAND_MAX;
|
||||
double newValue;
|
||||
if (pCF && pCF < pCFE) {
|
||||
newValue = *pCF++;
|
||||
}
|
||||
else {
|
||||
newValue = 0.0f;
|
||||
}
|
||||
newValue += (float) (sin (radians) / 10.0);
|
||||
limit = (float) this->info.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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user