Merged changes from the 3.14 branch, to revno 12674
This commit is contained in:
@@ -105,13 +105,17 @@ endif
|
||||
PRODTARGETS += $(PRODNAME) $(MUNCHNAME) $(CTDT_SRCS) $(CTDT_OBJS) $(NMS)
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Generate a test specification if any tests are defined.
|
||||
# Test specifications and test result files
|
||||
#
|
||||
ifneq (,$(strip $(TESTS)))
|
||||
TARGETS += testspec
|
||||
endif
|
||||
|
||||
# Enable testing if this host can run tests on the current target
|
||||
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
|
||||
RUNTESTS_ENABLED = YES
|
||||
TAPFILES += $(TESTSCRIPTS:.t=.tap)
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Libraries
|
||||
@@ -324,7 +328,7 @@ $(MODNAME): %$(MODEXT): %$(EXE)
|
||||
# Automated testing
|
||||
|
||||
runtests: $(TESTSCRIPTS)
|
||||
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
|
||||
ifdef RUNTESTS_ENABLED
|
||||
-$(PERL) -MTest::Harness -e 'runtests @ARGV if @ARGV;' $^
|
||||
endif
|
||||
|
||||
@@ -340,7 +344,7 @@ tapfiles: $(TESTSCRIPTS) $(TAPFILES)
|
||||
|
||||
# A .tap file is the output from running the associated test script
|
||||
%.tap: %.t
|
||||
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
|
||||
ifdef RUNTESTS_ENABLED
|
||||
-$(PERL) $< -tap > $@
|
||||
endif
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ VALID_BUILDS = Host Ioc
|
||||
|
||||
CMPLR_CLASS = msvc
|
||||
|
||||
OPT_WHOLE_PROGRAM = YES
|
||||
|
||||
#-------------------------------------------------------
|
||||
|
||||
WINLINK = link
|
||||
@@ -42,11 +44,13 @@ WARN_CFLAGS_NO = -W1
|
||||
# -Ox maximum optimizations
|
||||
# -GL whole program optimization
|
||||
# -Oy- re-enable creation of frame pointers
|
||||
OPT_CFLAGS_YES = -Ox -GL -Oy-
|
||||
OPT_CFLAGS_YES_YES = -Ox -GL -Oy-
|
||||
OPT_CFLAGS_YES_NO = -Ox -Oy-
|
||||
OPT_CFLAGS_YES = $(OPT_CFLAGS_YES_$(OPT_WHOLE_PROGRAM))
|
||||
|
||||
#
|
||||
# -Zi generate program database for debugging information
|
||||
# -RTCsu catch bugs occuring only inoptimized code
|
||||
# -RTCsu enable run-time error checks
|
||||
OPT_CFLAGS_NO = -Zi -RTCsu
|
||||
|
||||
# specify object file name and location
|
||||
@@ -96,17 +100,19 @@ CODE_CPPFLAGS += -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE
|
||||
# -w44355 set "'this' used in the base initializer list" to be level 4
|
||||
# -w44344 "behavior change: use of explicit template arguments results in ..."
|
||||
WARN_CXXFLAGS_YES = -W3 -w44355 -w44344
|
||||
WARN_CXXFLAGS_NO = -W1
|
||||
WARN_CXXFLAGS_NO = -W1
|
||||
|
||||
#
|
||||
# -Ox maximum optimizations
|
||||
# -GL whole program optimization
|
||||
# -Oy- re-enable creation of frame pointers
|
||||
OPT_CXXFLAGS_YES = -Ox -GL -Oy-
|
||||
OPT_CXXFLAGS_YES_YES = -Ox -GL -Oy-
|
||||
OPT_CXXFLAGS_YES_NO = -Ox -Oy-
|
||||
OPT_CXXFLAGS_YES = $(OPT_CXXFLAGS_YES_$(OPT_WHOLE_PROGRAM))
|
||||
|
||||
#
|
||||
# -Zi generate program database for debugging information
|
||||
# -RTCsu catch bugs occurring only in optimized code
|
||||
# -RTCsu enable run-time error checks
|
||||
OPT_CXXFLAGS_NO = -RTCsu -Zi
|
||||
|
||||
# specify object file name and location
|
||||
@@ -136,11 +142,14 @@ RANLIB=
|
||||
# -fixed:no generate relocatable code
|
||||
# -version:<major>.<minor> - only 2 components allowed, 0-65535 each
|
||||
# -debug generate debugging info
|
||||
LINK_OPT_FLAGS_YES = -LTCG -incremental:no -opt:ref \
|
||||
-release $(PROD_VERSION:%=-version:%)
|
||||
LINK_OPT_FLAGS_WHOLE_YES = -LTCG
|
||||
LINK_OPT_FLAGS_YES = $(LINK_OPT_FLAGS_WHOLE_$(OPT_WHOLE_PROGRAM))
|
||||
LINK_OPT_FLAGS_YES += -incremental:no -opt:ref
|
||||
LINK_OPT_FLAGS_YES += -release $(PROD_VERSION:%=-version:%)
|
||||
LINK_OPT_FLAGS_NO = -debug -incremental:no -fixed:no
|
||||
OPT_LDFLAGS = $(LINK_OPT_FLAGS_$(HOST_OPT))
|
||||
LIB_OPT_FLAGS_YES = -LTCG
|
||||
|
||||
LIB_OPT_FLAGS_YES = $(LINK_OPT_FLAGS_WHOLE_$(OPT_WHOLE_PROGRAM))
|
||||
LIB_OPT_LDFLAGS = $(LIB_OPT_FLAGS_$(HOST_OPT))
|
||||
|
||||
ARCH_DEP_CFLAGS=
|
||||
|
||||
8
configure/os/CONFIG_SITE.Common.win32-x86-static
Normal file
8
configure/os/CONFIG_SITE.Common.win32-x86-static
Normal file
@@ -0,0 +1,8 @@
|
||||
# CONFIG_SITE.Common.win32-x86-static
|
||||
#
|
||||
# Site-specific settings for the win32-x86-static target
|
||||
|
||||
# Whole-program optimization doesn't work with Visual Studio 2010 when
|
||||
# building static binaries. Newer versions of Visual Studio than 2010
|
||||
# may work though, comment out or set this to YES to try.
|
||||
OPT_WHOLE_PROGRAM = NO
|
||||
@@ -1,9 +1,8 @@
|
||||
# CONFIG_SITE.Common.windows-x64-static
|
||||
#
|
||||
# Site Specific definitions for windows-x64-static target
|
||||
# Only the local epics system manager should modify this file
|
||||
|
||||
# 64-bit Visual Studio 2010 builds fail when built optimized.
|
||||
# If you are using a newer version you can try removing this:
|
||||
HOST_OPT = NO
|
||||
# Site-specific settings for the windows-x64-static target
|
||||
|
||||
# Whole-program optimization doesn't work with Visual Studio 2010 when
|
||||
# building static binaries. Newer versions of Visual Studio than 2010
|
||||
# may work though, comment out or set this to YES to try.
|
||||
OPT_WHOLE_PROGRAM = NO
|
||||
|
||||
@@ -32,6 +32,29 @@ of the dbStatic library that is not being built anymore.</p>
|
||||
<h2 align="center">Changes from the 3.14 branch since 3.15.4</h2>
|
||||
<!-- Insert inherited items immediately below here ... -->
|
||||
|
||||
<h3>Add dynamic (variable length) array support to PCAS</h3>
|
||||
|
||||
<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 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>
|
||||
|
||||
<p>The EPICS timestamp library (epicsTime) inside libCom's OSI layer has
|
||||
been extended by routines that convert from <tt>struct tm</tt> to the EPICS
|
||||
internal <tt>epicsTime</tt> type, assuming UTC - i.e. without going through
|
||||
the timezone mechanism. This solves issues with converting from the structured
|
||||
type to the EPICS timestamp at driver level from multiple threads at a high
|
||||
repetition rate, where the timezone mechanism was blocking on file access.</p>
|
||||
|
||||
<h3>MinGW Cross-builds from Linux</h3>
|
||||
|
||||
<p>The build configuration files that allow cross-building of the 32-bit
|
||||
|
||||
@@ -149,9 +149,9 @@ cac::cac (
|
||||
iiuExistenceCount ( 0u ),
|
||||
cacShutdownInProgress ( false )
|
||||
{
|
||||
if ( ! osiSockAttach () ) {
|
||||
throwWithLocation ( caErrorCode (ECA_INTERNAL) );
|
||||
}
|
||||
if ( ! osiSockAttach () ) {
|
||||
throwWithLocation ( udpiiu :: noSocket () );
|
||||
}
|
||||
|
||||
try {
|
||||
long status;
|
||||
|
||||
@@ -61,11 +61,6 @@ static const double CA_CONN_VERIFY_PERIOD = 30.0; /* (sec) how often to request
|
||||
*/
|
||||
static const unsigned contiguousMsgCountWhichTriggersFlowControl = 10u;
|
||||
|
||||
class caErrorCode {
|
||||
public:
|
||||
caErrorCode ( int ) {};
|
||||
};
|
||||
|
||||
/*
|
||||
* CA internal functions
|
||||
*/
|
||||
|
||||
@@ -44,12 +44,7 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
#if 0
|
||||
const unsigned mSecPerSec = 1000u;
|
||||
const unsigned uSecPerSec = 1000u * mSecPerSec;
|
||||
#endif
|
||||
|
||||
tcpSendThread::tcpSendThread (
|
||||
tcpSendThread::tcpSendThread (
|
||||
class tcpiiu & iiuIn, const char * pName,
|
||||
unsigned stackSize, unsigned priority ) :
|
||||
thread ( *this, pName, stackSize, priority ), iiu ( iiuIn )
|
||||
@@ -807,28 +802,6 @@ tcpiiu::tcpiiu (
|
||||
}
|
||||
}
|
||||
|
||||
# if 0
|
||||
//
|
||||
// windows has a really strange implementation of thess options
|
||||
// and we can avoid the need for this by using pthread_kill on unix
|
||||
//
|
||||
{
|
||||
struct timeval timeout;
|
||||
double pollInterval = connectionTimeout / 8.0;
|
||||
timeout.tv_sec = static_cast < long > ( pollInterval );
|
||||
timeout.tv_usec = static_cast < long >
|
||||
( ( pollInterval - timeout.tv_sec ) * uSecPerSec );
|
||||
// intentionally ignore status as we dont expect that all systems
|
||||
// will accept this request
|
||||
setsockopt ( this->sock, SOL_SOCKET, SO_SNDTIMEO,
|
||||
( char * ) & timeout, sizeof ( timeout ) );
|
||||
// intentionally ignore status as we dont expect that all systems
|
||||
// will accept this request
|
||||
setsockopt ( this->sock, SOL_SOCKET, SO_RCVTIMEO,
|
||||
( char * ) & timeout, sizeof ( timeout ) );
|
||||
}
|
||||
# endif
|
||||
|
||||
if ( isNameService() ) {
|
||||
pSearchDest->setCircuit ( this );
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
static const unsigned char CA_MINOR_PROTOCOL_REVISION = 12;
|
||||
static const unsigned char CA_MINOR_PROTOCOL_REVISION = 13;
|
||||
|
||||
typedef ca_uint32_t caResId;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "caHdrLargeArray.h"
|
||||
|
||||
class casStrmClient;
|
||||
|
||||
class casCtx {
|
||||
public:
|
||||
casCtx();
|
||||
@@ -41,6 +43,7 @@ private:
|
||||
casChannelI * pChannel;
|
||||
casPVI * pPV;
|
||||
unsigned nAsyncIO; // checks for improper use of async io
|
||||
friend class casStrmClient;
|
||||
};
|
||||
|
||||
inline const caHdrLargeArray * casCtx::getMsg() const
|
||||
|
||||
@@ -388,14 +388,12 @@ caStatus casStrmClient::echoAction ( epicsGuard < casClientMutex > & )
|
||||
//
|
||||
// casStrmClient::verifyRequest()
|
||||
//
|
||||
caStatus casStrmClient::verifyRequest ( casChannelI * & pChan )
|
||||
caStatus casStrmClient::verifyRequest (casChannelI * & pChan , bool allowdyn)
|
||||
{
|
||||
const caHdrLargeArray * mp = this->ctx.getMsg();
|
||||
|
||||
//
|
||||
// channel exists for this resource id ?
|
||||
//
|
||||
chronIntId tmpId ( mp->m_cid );
|
||||
chronIntId tmpId ( ctx.msg.m_cid );
|
||||
pChan = this->chanTable.lookup ( tmpId );
|
||||
if ( ! pChan ) {
|
||||
return ECA_BADCHID;
|
||||
@@ -404,14 +402,15 @@ caStatus casStrmClient::verifyRequest ( casChannelI * & pChan )
|
||||
//
|
||||
// data type out of range ?
|
||||
//
|
||||
if ( mp->m_dataType > ((unsigned)LAST_BUFFER_TYPE) ) {
|
||||
if ( ctx.msg.m_dataType > ((unsigned)LAST_BUFFER_TYPE) ) {
|
||||
return ECA_BADTYPE;
|
||||
}
|
||||
|
||||
//
|
||||
// element count out of range ?
|
||||
//
|
||||
if ( mp->m_count > pChan->getPVI().nativeCount() || mp->m_count == 0u ) {
|
||||
if ( ctx.msg.m_count > pChan->getPVI().nativeCount() ||
|
||||
( !allowdyn && ctx.msg.m_count == 0u ) ) {
|
||||
return ECA_BADCOUNT;
|
||||
}
|
||||
|
||||
@@ -444,7 +443,7 @@ caStatus casStrmClient::readAction ( epicsGuard < casClientMutex > & guard )
|
||||
casChannelI * pChan;
|
||||
|
||||
{
|
||||
caStatus status = this->verifyRequest ( pChan );
|
||||
caStatus status = this->verifyRequest ( pChan, CA_V413 ( this->minor_version_number ) );
|
||||
if ( status != ECA_NORMAL ) {
|
||||
if ( pChan ) {
|
||||
return this->sendErr ( guard, mp, pChan->getCID(),
|
||||
@@ -531,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 ) {
|
||||
@@ -551,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 );
|
||||
}
|
||||
@@ -585,7 +588,7 @@ caStatus casStrmClient::readNotifyAction ( epicsGuard < casClientMutex > & guard
|
||||
casChannelI * pChan;
|
||||
|
||||
{
|
||||
caStatus status = this->verifyRequest ( pChan );
|
||||
caStatus status = this->verifyRequest ( pChan, CA_V413 ( this->minor_version_number ) );
|
||||
if ( status != ECA_NORMAL ) {
|
||||
return this->readNotifyFailureResponse ( guard, * mp, status );
|
||||
}
|
||||
@@ -656,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 ) {
|
||||
@@ -675,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 );
|
||||
}
|
||||
@@ -727,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() ) {
|
||||
@@ -755,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;
|
||||
@@ -770,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
|
||||
@@ -799,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;
|
||||
@@ -849,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 ) {
|
||||
@@ -871,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 ) {
|
||||
@@ -892,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 );
|
||||
}
|
||||
}
|
||||
@@ -915,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 (
|
||||
@@ -932,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 );
|
||||
}
|
||||
@@ -1940,7 +1952,7 @@ caStatus casStrmClient::eventAddAction (
|
||||
|
||||
casChannelI *pciu;
|
||||
{
|
||||
caStatus status = casStrmClient::verifyRequest ( pciu );
|
||||
caStatus status = casStrmClient::verifyRequest ( pciu, CA_V413 ( this->minor_version_number ) );
|
||||
if ( status != ECA_NORMAL ) {
|
||||
if ( pciu ) {
|
||||
return this->sendErr ( guard, mp,
|
||||
@@ -2601,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;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ private:
|
||||
bool responseIsPending;
|
||||
|
||||
caStatus createChannel ( const char * pName );
|
||||
caStatus verifyRequest ( casChannelI * & pChan );
|
||||
caStatus verifyRequest ( casChannelI * & pChan, bool allowdyn = false );
|
||||
typedef caStatus ( casStrmClient :: * pCASMsgHandler )
|
||||
( epicsGuard < casClientMutex > & );
|
||||
static pCASMsgHandler const msgHandlers[CA_PROTO_LAST_CMMD+1u];
|
||||
|
||||
@@ -60,11 +60,13 @@ static const unsigned long NTP_TIME_AT_EPICS_EPOCH =
|
||||
//
|
||||
// epicsTime (const unsigned long secIn, const unsigned long nSecIn)
|
||||
//
|
||||
inline epicsTime::epicsTime (const unsigned long secIn,
|
||||
const unsigned long nSecIn) :
|
||||
secPastEpoch ( nSecIn / nSecPerSec + secIn ),
|
||||
nSec ( nSecIn % nSecPerSec )
|
||||
inline epicsTime::epicsTime (const unsigned long secIn, const unsigned long nSecIn) :
|
||||
secPastEpoch ( secIn ), nSec ( nSecIn )
|
||||
{
|
||||
if (nSecIn >= nSecPerSec) {
|
||||
this->secPastEpoch += nSecIn / nSecPerSec;
|
||||
this->nSec = nSecIn % nSecPerSec;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -113,47 +115,26 @@ epicsTimeLoadTimeInit::epicsTimeLoadTimeInit ()
|
||||
}
|
||||
|
||||
//
|
||||
// epicsTime::addNanoSec ()
|
||||
// private epicsTime::addNanoSec ()
|
||||
//
|
||||
// The nano-second field of several of the the UNIX time stamp formats
|
||||
// field is stored in the C type "long".
|
||||
// Most formats keep the nSec value as an unsigned long, so are +ve.
|
||||
// struct timeval's tv_usec may be -1, but I think that means error,
|
||||
// so this private method never needs to handle -ve offsets.
|
||||
//
|
||||
void epicsTime :: addNanoSec ( long nSecAdj )
|
||||
{
|
||||
//
|
||||
// After optimizing this function we now have a larger code which
|
||||
// uses only unsigned integer, and not floating point, arithmetic.
|
||||
// This change benefits embedded CPU's lacking a floating point
|
||||
// co-processor at the expense of some additional code to maintain.
|
||||
//
|
||||
// We hope that all CPU's we run on provide at least an integer
|
||||
// divide instruction which should enable this implementation
|
||||
// to be more efficient than implementations based on branching;
|
||||
// this is presuming that we will run on pipelined architectures.
|
||||
//
|
||||
// Overflow and underflow is expected; in the future we might
|
||||
// operate close to, the modulo of, the EPICS epic.
|
||||
//
|
||||
// We are depending on the normalize operation in the private
|
||||
// constructor used below.
|
||||
//
|
||||
// joh 11-04-2012
|
||||
//
|
||||
if ( nSecAdj >= 0 ) {
|
||||
const unsigned long nSecPlus =
|
||||
static_cast <unsigned long> ( nSecAdj );
|
||||
const unsigned long nSecPlusAdj = nSecPlus % nSecPerSec;
|
||||
const unsigned long secPlusAdj = nSecPlus / nSecPerSec;
|
||||
*this = epicsTime ( this->secPastEpoch+secPlusAdj,
|
||||
this->nSec+nSecPlusAdj );
|
||||
if (nSecAdj <= 0)
|
||||
return;
|
||||
|
||||
if (static_cast<unsigned long>(nSecAdj) >= nSecPerSec) {
|
||||
this->secPastEpoch += nSecAdj / nSecPerSec;
|
||||
nSecAdj %= nSecPerSec;
|
||||
}
|
||||
else {
|
||||
const unsigned long nSecMinus =
|
||||
static_cast <unsigned long> ( -nSecAdj );
|
||||
const unsigned long nSecMinusAdj = nSecMinus % nSecPerSec;
|
||||
const unsigned long secMinusAdj = nSecMinus / nSecPerSec;
|
||||
*this = epicsTime ( this->secPastEpoch - secMinusAdj - 1u,
|
||||
this->nSec + nSecPerSec - nSecMinusAdj );
|
||||
|
||||
this->nSec += nSecAdj; // Can't overflow
|
||||
if (this->nSec >= nSecPerSec) {
|
||||
this->secPastEpoch++;
|
||||
this->nSec -= nSecPerSec;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,20 +298,82 @@ epicsTime::operator gm_tm_nano_sec () const
|
||||
//
|
||||
epicsTime::epicsTime (const local_tm_nano_sec &tm)
|
||||
{
|
||||
static const time_t mktimeFailure = static_cast <time_t> (-1);
|
||||
time_t_wrapper ansiTimeTicks;
|
||||
struct tm tmp = tm.ansi_tm;
|
||||
time_t_wrapper ansiTimeTicks = { mktime (&tmp) };
|
||||
|
||||
ansiTimeTicks.ts = mktime (&tmp);
|
||||
if (ansiTimeTicks.ts == mktimeFailure) {
|
||||
static const time_t mktimeError = static_cast <time_t> (-1);
|
||||
if (ansiTimeTicks.ts == mktimeError) {
|
||||
throwWithLocation ( formatProblemWithStructTM () );
|
||||
}
|
||||
|
||||
*this = epicsTime (ansiTimeTicks);
|
||||
*this = epicsTime(ansiTimeTicks);
|
||||
this->addNanoSec(tm.nSec);
|
||||
}
|
||||
|
||||
unsigned long nSecAdj = tm.nSec % nSecPerSec;
|
||||
unsigned long secAdj = tm.nSec / nSecPerSec;
|
||||
*this = epicsTime ( this->secPastEpoch+secAdj, this->nSec+nSecAdj );
|
||||
//
|
||||
// epicsTime (const gm_tm_nano_sec &tm)
|
||||
//
|
||||
|
||||
// do conversion avoiding the timezone mechanism
|
||||
static inline int is_leap(int year)
|
||||
{
|
||||
if (year % 400 == 0)
|
||||
return 1;
|
||||
if (year % 100 == 0)
|
||||
return 0;
|
||||
if (year % 4 == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int days_from_0(int year)
|
||||
{
|
||||
year--;
|
||||
return 365 * year + (year / 400) - (year / 100) + (year / 4);
|
||||
}
|
||||
|
||||
static inline int days_from_1970(int year)
|
||||
{
|
||||
static const int days_from_0_to_1970 = days_from_0(1970);
|
||||
return days_from_0(year) - days_from_0_to_1970;
|
||||
}
|
||||
|
||||
static inline int days_from_1jan(int year, int month, int day)
|
||||
{
|
||||
static const int days[2][12] =
|
||||
{
|
||||
{ 0,31,59,90,120,151,181,212,243,273,304,334},
|
||||
{ 0,31,60,91,121,152,182,213,244,274,305,335}
|
||||
};
|
||||
return days[is_leap(year)][month-1] + day - 1;
|
||||
}
|
||||
|
||||
epicsTime::epicsTime (const gm_tm_nano_sec &tm)
|
||||
{
|
||||
int year = tm.ansi_tm.tm_year + 1900;
|
||||
int month = tm.ansi_tm.tm_mon;
|
||||
if (month > 11) {
|
||||
year += month / 12;
|
||||
month %= 12;
|
||||
} else if (month < 0) {
|
||||
int years_diff = (-month + 11) / 12;
|
||||
year -= years_diff;
|
||||
month += 12 * years_diff;
|
||||
}
|
||||
month++;
|
||||
|
||||
int day = tm.ansi_tm.tm_mday;
|
||||
int day_of_year = days_from_1jan(year, month, day);
|
||||
int days_since_epoch = days_from_1970(year) + day_of_year;
|
||||
|
||||
time_t_wrapper ansiTimeTicks;
|
||||
ansiTimeTicks.ts = ((days_since_epoch
|
||||
* 24 + tm.ansi_tm.tm_hour)
|
||||
* 60 + tm.ansi_tm.tm_min)
|
||||
* 60 + tm.ansi_tm.tm_sec;
|
||||
|
||||
*this = epicsTime(ansiTimeTicks);
|
||||
this->addNanoSec(tm.nSec);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -729,7 +772,7 @@ double epicsTime::operator - (const epicsTime &rhs) const
|
||||
// so the unsigned to signed conversion is ok
|
||||
//
|
||||
if (this->nSec>=rhs.nSec) {
|
||||
nSecRes = this->nSec - rhs.nSec;
|
||||
nSecRes = this->nSec - rhs.nSec;
|
||||
}
|
||||
else {
|
||||
nSecRes = rhs.nSec - this->nSec;
|
||||
@@ -944,6 +987,19 @@ extern "C" {
|
||||
}
|
||||
return epicsTimeOK;
|
||||
}
|
||||
epicsShareFunc int epicsShareAPI epicsTimeFromGMTM (epicsTimeStamp *pDest, const struct tm *pSrc, unsigned long nSecSrc)
|
||||
{
|
||||
try {
|
||||
gm_tm_nano_sec tmns;
|
||||
tmns.ansi_tm = *pSrc;
|
||||
tmns.nSec = nSecSrc;
|
||||
*pDest = epicsTime (tmns);
|
||||
}
|
||||
catch (...) {
|
||||
return epicsTimeERROR;
|
||||
}
|
||||
return epicsTimeOK;
|
||||
}
|
||||
epicsShareFunc int epicsShareAPI epicsTimeToTimespec (struct timespec *pDest, const epicsTimeStamp *pSrc)
|
||||
{
|
||||
try {
|
||||
@@ -1075,4 +1131,3 @@ extern "C" {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,10 +105,12 @@ public:
|
||||
epicsTime & operator = ( const local_tm_nano_sec & );
|
||||
|
||||
/*
|
||||
* convert to ANSI Cs "struct tm" (with nano seconds)
|
||||
* convert to and from ANSI Cs "struct tm" (with nano seconds)
|
||||
* adjusted for GM time (UTC)
|
||||
*/
|
||||
operator gm_tm_nano_sec () const;
|
||||
epicsTime ( const gm_tm_nano_sec & );
|
||||
epicsTime & operator = ( const gm_tm_nano_sec & );
|
||||
|
||||
/* convert to and from POSIX RTs "struct timespec" */
|
||||
operator struct timespec () const;
|
||||
@@ -194,13 +196,15 @@ epicsShareFunc int epicsShareAPI epicsTimeToTime_t (
|
||||
epicsShareFunc int epicsShareAPI epicsTimeFromTime_t (
|
||||
epicsTimeStamp * pDest, time_t src );
|
||||
|
||||
/*convert to and from ANSI C's "struct tm" with nano seconds */
|
||||
/* convert to and from ANSI C's "struct tm" with nano seconds */
|
||||
epicsShareFunc int epicsShareAPI epicsTimeToTM (
|
||||
struct tm * pDest, unsigned long * pNSecDest, const epicsTimeStamp * pSrc );
|
||||
epicsShareFunc int epicsShareAPI epicsTimeToGMTM (
|
||||
struct tm * pDest, unsigned long * pNSecDest, const epicsTimeStamp * pSrc );
|
||||
epicsShareFunc int epicsShareAPI epicsTimeFromTM (
|
||||
epicsTimeStamp * pDest, const struct tm * pSrc, unsigned long nSecSrc );
|
||||
epicsShareFunc int epicsShareAPI epicsTimeFromGMTM (
|
||||
epicsTimeStamp * pDest, const struct tm * pSrc, unsigned long nSecSrc );
|
||||
|
||||
/* convert to and from POSIX RT's "struct timespec" */
|
||||
epicsShareFunc int epicsShareAPI epicsTimeToTimespec (
|
||||
@@ -312,6 +316,11 @@ inline epicsTime & epicsTime::operator = ( const local_tm_nano_sec & rhs )
|
||||
return *this = epicsTime ( rhs );
|
||||
}
|
||||
|
||||
inline epicsTime & epicsTime::operator = ( const gm_tm_nano_sec & rhs )
|
||||
{
|
||||
return *this = epicsTime ( rhs );
|
||||
}
|
||||
|
||||
inline epicsTime & epicsTime::operator = ( const struct timespec & rhs )
|
||||
{
|
||||
*this = epicsTime ( rhs );
|
||||
|
||||
@@ -43,7 +43,7 @@ MAIN(epicsTimeTest)
|
||||
const int wasteTime = 100000;
|
||||
const int nTimes = 10;
|
||||
|
||||
testPlan(15 + nTimes * 18);
|
||||
testPlan(15 + nTimes * 19);
|
||||
|
||||
try {
|
||||
const epicsTimeStamp epochTS = {0, 0};
|
||||
@@ -200,6 +200,11 @@ MAIN(epicsTimeTest)
|
||||
epicsTime beginANSI = ansiDate;
|
||||
testOk1(beginANSI + diff == now);
|
||||
|
||||
// test struct gmtm round-trip conversion
|
||||
gm_tm_nano_sec ansiGmDate = begin;
|
||||
epicsTime beginGMANSI = ansiGmDate;
|
||||
testOk1(beginGMANSI + diff == now);
|
||||
|
||||
// test struct timespec round-trip conversion
|
||||
struct timespec ts = begin;
|
||||
epicsTime beginTS = ts;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
if (dimension==0u) {
|
||||
return this->info.getElementCount();
|
||||
return this->info.getCapacity();
|
||||
}
|
||||
else {
|
||||
return 0u;
|
||||
@@ -60,26 +59,21 @@ aitIndex exVectorPV::maxBound (unsigned dimension) const
|
||||
//
|
||||
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