added vector support

This commit is contained in:
Jeff Hill
1996-12-11 01:07:17 +00:00
parent fa64c5bdd2
commit dff79f6bea
8 changed files with 504 additions and 224 deletions

View File

@@ -19,7 +19,8 @@ DEPLIBS = $(DEPLIBS_BASE)/libcas.a $(DEPLIBSWOCAS)
SRCS.cc += ../main.cc
SRCS.cc += ../exServer.cc
SRCS.cc += ../exPV.cc
SRCS.cc += ../exSyncPV.cc
SRCS.cc += ../exVectorPV.cc
SRCS.cc += ../exScalarPV.cc
SRCS.cc += ../exAsyncPV.cc
SRCS.cc += ../exChannel.cc
SRCS.cc += ../templInst.cc
@@ -27,7 +28,8 @@ SRCS.cc += ../templInst.cc
OBJS += main.o
OBJS += exServer.o
OBJS += exPV.o
OBJS += exSyncPV.o
OBJS += exVectorPV.o
OBJS += exScalarPV.o
OBJS += exAsyncPV.o
OBJS += exChannel.o
OBJS += templInst.o

View File

@@ -5,8 +5,6 @@
#include <exServer.h>
#include <gddApps.h>
const double myPI = 3.14159265358979323846;
osiTime exPV::currentTime;
//
@@ -20,9 +18,9 @@ exPV::exPV (const casCtx &ctxIn, const pvInfo &setup) :
interest(aitFalse)
{
//
// load initial value
// no dataless PV allowed
//
this->scanPV();
assert (this->info.getElementCount()>=1u);
}
//
@@ -41,55 +39,46 @@ exPV::~exPV()
}
//
// exPV::scanPV();
// exPV::update()
//
void exPV::scanPV()
caStatus exPV::update(gdd &valueIn)
{
caStatus status;
double radians;
gdd *pDD;
float newValue;
float limit;
caServer *pCAS = this->getCAS();
caServer *pCAS = this->getCAS();
//
// gettimeofday() is very slow under sunos4
//
osiTime cur (this->currentTime);
struct timespec t;
caStatus cas;
if (!pCAS) {
return S_casApp_noSupport;
}
# if DEBUG
printf("Setting %s too:\n", this->info.getName().string());
valueIn.dump();
# endif
if (!pCAS) {
return;
cas = this->updateValue (valueIn);
if (cas || !this->pValue) {
return cas;
}
cur.get (t.tv_sec, t.tv_nsec);
this->pValue->setTimeStamp(&t);
this->pValue->setStat (epicsAlarmNone);
this->pValue->setSevr (epicsSevNone);
//
// 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)
// post a value change event
//
this->currentTime = osiTime::getCurrent();
pDD = new gddScalar (gddAppType_value, aitEnumFloat32);
if (!pDD) {
return;
}
radians = (rand () * 2.0 * myPI)/RAND_MAX;
if (this->pValue) {
this->pValue->getConvert(newValue);
}
else {
newValue = 0.0f;
}
newValue += (float) (sin (radians) / 10.0);
limit = (float) this->info.getHopr();
newValue = min (newValue, limit);
limit = (float) this->info.getLopr();
newValue = max (newValue, limit);
*pDD = newValue;
pDD->setStat (epicsAlarmNone);
pDD->setSevr (epicsSevNone);
status = this->update (*pDD);
if (status) {
errMessage (status, "scan update failed\n");
}
pDD->unreference();
if (this->interest==aitTrue) {
casEventMask select(pCAS->valueEventMask|pCAS->logEventMask);
this->postEvent (select, *this->pValue);
}
return S_casApp_success;
}
//
@@ -97,7 +86,7 @@ void exPV::scanPV()
//
void exScanTimer::expire ()
{
pv.scanPV();
pv.scan();
}
//
@@ -124,77 +113,6 @@ const char *exScanTimer::name() const
return "exScanTimer";
}
//
// exPV::update ()
//
caStatus exPV::update(gdd &valueIn)
{
gdd *pNewValue;
caServer *pCAS = this->getCAS();
//
// gettimeofday() is very slow under sunos4
//
osiTime cur (this->currentTime);
struct timespec t;
gddStatus gdds;
if (!pCAS) {
return S_casApp_noSupport;
}
# if DEBUG
printf("Setting %s too:\n", this->info.getName().string());
valueIn.dump();
# endif
if (valueIn.isScalar()) {
pNewValue = &valueIn;
pNewValue->reference();
}
else {
//
// this does not modify the current value
// (because it may be referenced in the event queue)
//
pNewValue = new gddScalar (gddAppType_value, aitEnumFloat32);
if (!pNewValue) {
return S_casApp_noMemory;
}
gdds = gddApplicationTypeTable::
app_table.smartCopy(pNewValue, &valueIn);
if (gdds) {
pNewValue->unreference();
return S_cas_noConvert;
}
pNewValue->setStat (epicsAlarmNone);
pNewValue->setSevr (epicsSevNone);
}
cur.get (t.tv_sec, t.tv_nsec);
pNewValue->setTimeStamp(&t);
//
// release old value and replace it
// with the new one
//
if (this->pValue) {
this->pValue->unreference();
}
this->pValue = pNewValue;
if (this->interest==aitTrue) {
casEventMask select(pCAS->valueEventMask|pCAS->logEventMask);
this->postEvent (select, *this->pValue);
}
return S_casApp_success;
}
//
// exPV::bestExternalType()
//
@@ -354,7 +272,7 @@ caStatus exPV::getLowLimit(gdd &value)
//
caStatus exPV::getUnits(gdd &units)
{
static aitString str("@#$%");
static aitString str("furlongs");
units.put(str);
return S_cas_success;
}
@@ -392,3 +310,19 @@ caStatus exPV::getValue(gdd &value)
return status;
}
//
// exPV::write()
//
caStatus exPV::write (const casCtx &, gdd &valueIn)
{
return this->update (valueIn);
}
//
// exPV::read()
//
caStatus exPV::read (const casCtx &, gdd &protoIn)
{
return exServer::read(*this, protoIn);
}

View File

@@ -0,0 +1,99 @@
#include <exServer.h>
#include <gddApps.h>
#include <math.h>
#include <limits.h>
#include <stdlib.h>
#define myPI 3.14159265358979323846
//
// SUN C++ does not have RAND_MAX yet
//
#if !defined(RAND_MAX)
//
// Apparently SUN C++ is using the SYSV version of rand
//
#if 0
#define RAND_MAX INT_MAX
#else
#define RAND_MAX SHRT_MAX
#endif
#endif
//
// exScalarPV::scan
//
void exScalarPV::scan()
{
caStatus status;
double radians;
gdd *pDD;
float newValue;
float limit;
//
// 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)
//
this->currentTime = osiTime::getCurrent();
pDD = new gddScalar (gddAppType_value, aitEnumFloat32);
if (!pDD) {
return;
}
radians = (rand () * 2.0 * myPI)/RAND_MAX;
if (this->pValue) {
this->pValue->getConvert(newValue);
}
else {
newValue = 0.0f;
}
newValue += (float) (sin (radians) / 10.0);
limit = (float) this->info.getHopr();
newValue = min (newValue, limit);
limit = (float) this->info.getLopr();
newValue = max (newValue, limit);
*pDD = newValue;
status = this->update (*pDD);
if (status) {
errMessage (status, "scan update failed\n");
}
pDD->unreference();
}
//
// exScalarPV::updateValue ()
//
// NOTES:
// 1) This should have a test which verifies that the
// incoming value in all of its various data types can
// be translated into a real number?
// 2) We prefer to unreference the old PV value here and
// reference the incomming value because this will
// result in value change events each retaining an
// independent value on the event queue.
//
caStatus exScalarPV::updateValue (gdd &valueIn)
{
if (!valueIn.isScalar()) {
return S_casApp_outOfBounds;
}
//
// release old value and replace it
// with the new one
//
if (this->pValue) {
this->pValue->unreference();
}
valueIn.reference();
this->pValue = &valueIn;
return S_casApp_success;
}

View File

@@ -10,10 +10,12 @@
#include <exServer.h>
const pvInfo exServer::pvList[] = {
pvInfo (1.0e-1, "jane", 10.0f, 0.0f, excasIoSync),
pvInfo (2.0, "fred", 10.0f, -10.0f, excasIoSync),
pvInfo (1.0e-1, "janet", 10.0f, 0.0f, excasIoAsync),
pvInfo (2.0, "freddy", 10.0f, -10.0f, excasIoAsync)
pvInfo (1.0e-1, "jane", 10.0f, 0.0f, excasIoSync, 1u),
pvInfo (2.0, "fred", 10.0f, -10.0f, excasIoSync, 1u),
pvInfo (1.0e-1, "janet", 10.0f, 0.0f, excasIoAsync, 1u),
pvInfo (2.0, "freddy", 10.0f, -10.0f, excasIoAsync, 1u),
pvInfo (2.0, "alan", 10.0f, -10.0f, excasIoSync, 100u),
pvInfo (20.0, "albert", 10.0f, -10.0f, excasIoSync, 1000u)
};
//
@@ -96,20 +98,45 @@ const pvInfo *exServer::findPV(const char *pName)
casPV *exServer::createPV (const casCtx &ctxIn, const char *pPVName)
{
const pvInfo *pInfo;
exPV *pPV;
pInfo = exServer::findPV(pPVName);
if (!pInfo) {
return NULL;
}
switch (pInfo->getIOType()){
case excasIoSync:
return new exSyncPV (ctxIn, *pInfo);
case excasIoAsync:
return new exAsyncPV (ctxIn, *pInfo);
default:
return NULL;
//
// create an instance of the appropriate class
// depending on the io type and the number
// of elements
//
if (pInfo->getElementCount()==1u) {
switch (pInfo->getIOType()){
case excasIoSync:
pPV = new exScalarPV (ctxIn, *pInfo);
break;
case excasIoAsync:
pPV = new exAsyncPV (ctxIn, *pInfo);
break;
default:
pPV = NULL;
break;
}
}
else {
pPV = new exVectorPV (ctxIn, *pInfo);
}
//
// load initial value (this is not done in
// the constructor because the base class's
// pure virtual function would be called)
//
if (pPV) {
pPV->scan();
}
return pPV;
}
//

View File

@@ -1,29 +1,27 @@
//
// Example EPICS CA server
// Example EPICS CA server
//
//
// caServer
// |
// exServer
//
// casPV
// |
// exPV-------------
// | |
// exScalarPV exVectorPV
// |
// exAsyncPV
//
//
//
// ANSI C
//
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
//
// SUN C++ does not have RAND_MAX yet
//
#if !defined(RAND_MAX)
//
// Apparently SUN C++ is using the SYSV version of rand
//
#if 0
#define RAND_MAX INT_MAX
#else
#define RAND_MAX SHRT_MAX
#endif
#endif
//
// EPICS
@@ -56,20 +54,20 @@ class pvInfo {
public:
pvInfo (double scanRateIn, const char *pName,
aitFloat32 hoprIn, aitFloat32 loprIn,
excasIoType ioTypeIn) :
excasIoType ioTypeIn, unsigned countIn) :
scanRate(scanRateIn), name(pName), hopr(hoprIn),
lopr(loprIn), ioType(ioTypeIn)
lopr(loprIn), ioType(ioTypeIn), elementCount(countIn)
{
}
//
// for use when MSVC++ will not build a defualt copy constructor
// for use when MSVC++ will not build a default copy constructor
// for this class
//
pvInfo (const pvInfo &copyIn) :
scanRate(copyIn.scanRate), name(copyIn.name),
hopr(copyIn.hopr), lopr(copyIn.lopr),
ioType(copyIn.ioType)
ioType(copyIn.ioType), elementCount(copyIn.elementCount)
{
}
@@ -78,12 +76,14 @@ public:
const double getHopr () const { return this->hopr; }
const double getLopr () const { return this->lopr; }
const excasIoType getIOType () const { return this->ioType; }
const unsigned getElementCount() const { return this->elementCount; }
private:
const double scanRate;
const aitString name;
const double hopr;
const double lopr;
const excasIoType ioType;
const unsigned elementCount;
};
class exPV;
@@ -113,8 +113,6 @@ public:
exPV (const casCtx &ctxIn, const pvInfo &setup);
virtual ~exPV();
void scanPV();
void show(unsigned level);
//
@@ -143,8 +141,16 @@ public:
//
//casChannel *createChannel ();
//
// This gets called when the pv gets a new value
//
caStatus update (gdd &value);
//
// Gets called when we add noise to the current value
//
virtual void scan() = 0;
//
// Std PV Attribute fetch support
//
@@ -168,13 +174,47 @@ public:
{
return this->info.getScanRate();
}
caStatus read (const casCtx &, gdd &protoIn);
caStatus write (const casCtx &, gdd &protoIn);
protected:
gdd *pValue;
exScanTimer *pScanTimer;
const pvInfo & info;
aitBool interest;
private:
static osiTime currentTime;
virtual caStatus updateValue (gdd &value) = 0;
};
//
// exScalerPV
//
class exScalarPV : public exPV {
public:
exScalarPV (const casCtx &ctxIn, const pvInfo &setup) :
exPV (ctxIn, setup) {}
void scan();
private:
caStatus updateValue (gdd &value);
};
//
// exVectorPV
//
class exVectorPV : public exPV {
public:
exVectorPV (const casCtx &ctxIn, const pvInfo &setup) :
exPV (ctxIn, setup) {}
void scan();
unsigned maxDimension() const;
aitIndex maxBound (unsigned dimension) const;
private:
caStatus updateValue (gdd &value);
};
//
@@ -199,37 +239,16 @@ private:
static gddAppFuncTable<exPV> ft;
};
//
// exSyncPV
//
class exSyncPV : public exPV {
public:
exSyncPV (const casCtx &ctxIn, const pvInfo &setup);
~exSyncPV();
//
// read
//
caStatus read(const casCtx &ctxIn, gdd &value);
//
// write
//
caStatus write(const casCtx &ctxIn, gdd &value);
private:
};
//
// exAsyncPV
// (asychronous PV)
//
class exAsyncPV : public exPV {
class exAsyncPV : public exScalarPV {
public:
//
// exAsyncPV()
//
exAsyncPV (const casCtx &ctxIn, const pvInfo &setup) :
exPV (ctxIn, setup) {}
exAsyncPV (const casCtx &ctxIn, const pvInfo &setup) :
exScalarPV (ctxIn, setup) {}
//
// read

View File

@@ -1,38 +0,0 @@
//
// Example EPICS CA server
//
#include <exServer.h>
//
// exSyncPV::exSyncPV()
//
exSyncPV::exSyncPV (const casCtx &ctxIn, const pvInfo &setup) :
exPV (ctxIn, setup)
{
}
//
// exSyncPV::~exSyncPV()
//
exSyncPV::~exSyncPV()
{
}
//
// exSyncPV::write()
//
caStatus exSyncPV::write (const casCtx &, gdd &valueIn)
{
return this->update (valueIn);
}
//
// exSyncPV::read()
//
caStatus exSyncPV::read (const casCtx &, gdd &protoIn)
{
return exServer::read(*this, protoIn);
}

View File

@@ -0,0 +1,237 @@
#include <exServer.h>
#include <gddApps.h>
#define myPI 3.14159265358979323846
//
// SUN C++ does not have RAND_MAX yet
//
#if !defined(RAND_MAX)
//
// Apparently SUN C++ is using the SYSV version of rand
//
#if 0
#define RAND_MAX INT_MAX
#else
#define RAND_MAX SHRT_MAX
#endif
#endif
//
// exVectorPV::maxDimension()
//
unsigned exVectorPV::maxDimension() const
{
return 1u;
}
//
// exVectorPV::maxBound()
//
aitIndex exVectorPV::maxBound (unsigned dimension) const
{
if (dimension==0u) {
return this->info.getElementCount();
}
else {
return 0u;
}
}
//
// exVectorPV::scan
//
void exVectorPV::scan()
{
caStatus status;
double radians;
gdd *pDD;
aitFloat32 *pF, *pFE, *pCF;
float newValue;
float limit;
//
// 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)
//
this->currentTime = osiTime::getCurrent();
pDD = new gddAtomic (gddAppType_value, aitEnumFloat32,
1u, this->info.getElementCount());
if (pDD==NULL) {
return;
}
//
// allocate array buffer
//
pF = new aitFloat32 [this->info.getElementCount()];
if (!pF) {
pDD->unreference();
}
//
// double check for reasonable bounds on the
// current value
//
pCF=NULL;
if (this->pValue) {
if (this->pValue->dimension()==1u) {
const gddBounds *pB = this->pValue->getBounds();
if (pB[0u].size()==this->info.getElementCount()) {
pCF = *pDD;
}
}
}
pFE = &pF[this->info.getElementCount()];
while (pF<pFE) {
radians = (rand () * 2.0 * myPI)/RAND_MAX;
if (pCF) {
newValue = *pCF++;
}
else {
newValue = 0.0f;
}
newValue += (float) (sin (radians) / 10.0);
limit = (float) this->info.getHopr();
newValue = min (newValue, limit);
limit = (float) this->info.getLopr();
newValue = max (newValue, limit);
*(pF++) = newValue;
}
//
// install the buffer into the DD
//
*pDD = pF;
status = this->update (*pDD);
if (status) {
errMessage (status, "scan update failed\n");
}
pDD->unreference();
}
//
// exVectorPV::updateValue ()
//
// NOTES:
// 1) This should have a test which verifies that the
// incoming value in all of its various data types can
// be translated into a real number?
// 2) We prefer to unreference the old PV value here and
// reference the incomming value because this will
// result in value change events each retaining an
// independent value on the event queue. With large arrays
// this may result in too much memory consumtion on
// the event queue.
//
caStatus exVectorPV::updateValue(gdd &valueIn)
{
enum {replace, dontReplace} replFlag = dontReplace;
gddStatus gdds;
gdd *pNewValue;
//
// Check bounds of incoming request
// (and see if we are replacing all elements -
// replaceOk==TRUE)
//
if (valueIn.isAtomic()) {
if (valueIn.dimension()!=1u) {
return S_casApp_badDimension;
}
const gddBounds* pb = valueIn.getBounds();
if (pb[0u].first()!=0u) {
return S_casApp_outOfBounds;
}
if (pb[0u].size()==this->info.getElementCount()) {
replFlag = replace;
}
else if (pb[0u].size()>this->info.getElementCount()) {
return S_casApp_outOfBounds;
}
}
else if (!valueIn.isScalar()) {
//
// no containers
//
return S_casApp_outOfBounds;
}
if (replFlag==replace) {
//
// It is most efficient to replace all elements
//
valueIn.reference();
pNewValue = &valueIn;
}
else {
aitFloat32 *pF, *pFE;
//
// Create a new array data descriptor
// (so that old values that may be referenced on the
// event queue are not replaced)
//
pNewValue = new gddAtomic (gddAppType_value, aitEnumFloat32,
1u, this->info.getElementCount());
if (pNewValue==NULL) {
return S_casApp_noMemory;
}
//
// copy over the old values if they exist
// (or initialize all elements to zero)
//
if (this->pValue) {
gdds = pNewValue->copy(this->pValue);
if (gdds) {
pNewValue->unreference();
return S_cas_noConvert;
}
}
else {
//
// allocate array buffer
//
pF = new aitFloat32 [this->info.getElementCount()];
if (!pF) {
pNewValue->unreference();
return S_casApp_noMemory;
}
//
// Install (and initialize) array buffer
// if no old values exist
//
pFE = &pF[this->info.getElementCount()];
while (pF<pFE) {
*(pF++) = 0.0;
}
*pNewValue = pF;
}
//
// insert the values that they are writing
//
gdds = pNewValue->put(&valueIn);
if (gdds) {
pNewValue->unreference();
return S_cas_noConvert;
}
}
if (this->pValue) {
this->pValue->unreference();
}
this->pValue = pNewValue;
return S_casApp_success;
}

View File

@@ -15,11 +15,6 @@ int main (int argc, const char **argv)
aitBool forever = aitTrue;
int i;
pCAS = new exServer(32u,5u,500u);
if (!pCAS) {
return (-1);
}
for (i=1; i<argc; i++) {
if (sscanf(argv[i], "-d %u", &debugLevel)==1) {
continue;
@@ -33,6 +28,11 @@ int main (int argc, const char **argv)
return (1);
}
pCAS = new exServer(32u,5u,500u);
if (!pCAS) {
return (-1);
}
pCAS->setDebugLevel(debugLevel);
if (forever) {