266 lines
6.0 KiB
C++
266 lines
6.0 KiB
C++
|
|
#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
|
|
|
|
//
|
|
// special gddDestructor guarantees same form of new and delete
|
|
//
|
|
class exVecDestructor: public gddDestructor {
|
|
virtual void run (void *);
|
|
};
|
|
|
|
//
|
|
// exVectorPV::maxDimension()
|
|
//
|
|
unsigned exVectorPV::maxDimension() const
|
|
{
|
|
return 1u;
|
|
}
|
|
|
|
//
|
|
// exVectorPV::maxBound()
|
|
//
|
|
aitIndex exVectorPV::maxBound (unsigned dimension) const // X aCC 361
|
|
{
|
|
if (dimension==0u) {
|
|
return this->info.getElementCount();
|
|
}
|
|
else {
|
|
return 0u;
|
|
}
|
|
}
|
|
|
|
//
|
|
// exVectorPV::scan
|
|
//
|
|
void exVectorPV::scan()
|
|
{
|
|
caStatus status;
|
|
double radians;
|
|
smartGDDPointer pDD;
|
|
aitFloat32 *pF, *pFE;
|
|
const aitFloat32 *pCF;
|
|
float newValue;
|
|
float limit;
|
|
exVecDestructor *pDest;
|
|
int gddStatus;
|
|
|
|
//
|
|
// 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 = epicsTime::getCurrent();
|
|
|
|
pDD = new gddAtomic (gddAppType_value, aitEnumFloat64,
|
|
1u, this->info.getElementCount());
|
|
if ( ! pDD.valid () ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// smart pointer class manages reference count after this point
|
|
//
|
|
gddStatus = pDD->unreference();
|
|
assert (!gddStatus);
|
|
|
|
//
|
|
// allocate array buffer
|
|
//
|
|
pF = new aitFloat32 [this->info.getElementCount()];
|
|
if (!pF) {
|
|
return;
|
|
}
|
|
|
|
pDest = new exVecDestructor;
|
|
if (!pDest) {
|
|
delete [] pF;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// install the buffer into the DD
|
|
// (do this before we increment pF)
|
|
//
|
|
pDD->putRef(pF, pDest);
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 = tsMin (newValue, limit);
|
|
limit = (float) this->info.getLopr();
|
|
newValue = tsMax (newValue, limit);
|
|
*(pF++) = newValue;
|
|
}
|
|
|
|
status = this->update (pDD);
|
|
if (status!=S_casApp_success) {
|
|
errMessage (status, "vector scan update failed\n");
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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(smartConstGDDPointer pValueIn)
|
|
{
|
|
gddStatus gdds;
|
|
smartGDDPointer pNewValue;
|
|
exVecDestructor *pDest;
|
|
unsigned i;
|
|
|
|
if ( ! pValueIn.valid () ) {
|
|
return S_casApp_undefined;
|
|
}
|
|
|
|
//
|
|
// Check bounds of incoming request
|
|
// (and see if we are replacing all elements -
|
|
// replaceOk==TRUE)
|
|
//
|
|
// Perhaps much of this is unnecessary since the
|
|
// server lib checks the bounds of all requests
|
|
//
|
|
if (pValueIn->isAtomic()) {
|
|
if (pValueIn->dimension()!=1u) {
|
|
return S_casApp_badDimension;
|
|
}
|
|
const gddBounds* pb = pValueIn->getBounds();
|
|
if (pb[0u].first()!=0u) {
|
|
return S_casApp_outOfBounds;
|
|
}
|
|
else if (pb[0u].size()>this->info.getElementCount()) {
|
|
return S_casApp_outOfBounds;
|
|
}
|
|
}
|
|
else if (!pValueIn->isScalar()) {
|
|
//
|
|
// no containers
|
|
//
|
|
return S_casApp_outOfBounds;
|
|
}
|
|
|
|
aitFloat64 *pF;
|
|
int gddStatus;
|
|
|
|
//
|
|
// 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, aitEnumFloat64,
|
|
1u, this->info.getElementCount());
|
|
if ( ! pNewValue.valid () ) {
|
|
return S_casApp_noMemory;
|
|
}
|
|
|
|
//
|
|
// smart pointer class takes care of the reference count
|
|
// from here down
|
|
//
|
|
gddStatus = pNewValue->unreference();
|
|
assert (!gddStatus);
|
|
|
|
//
|
|
// allocate array buffer
|
|
//
|
|
pF = new aitFloat64 [this->info.getElementCount()];
|
|
if (!pF) {
|
|
return S_casApp_noMemory;
|
|
}
|
|
|
|
//
|
|
// Install (and initialize) array buffer
|
|
// if no old values exist
|
|
//
|
|
unsigned count = this->info.getElementCount();
|
|
for ( i = 0u; i < count; i++ ) {
|
|
pF[i] = 0.0f;
|
|
}
|
|
|
|
pDest = new exVecDestructor;
|
|
if (!pDest) {
|
|
delete [] pF;
|
|
return S_casApp_noMemory;
|
|
}
|
|
|
|
//
|
|
// install the buffer into the DD
|
|
// (do this before we increment pF)
|
|
//
|
|
pNewValue->putRef(pF, pDest);
|
|
|
|
//
|
|
// copy in the values that they are writing
|
|
//
|
|
gdds = pNewValue->put( & (*pValueIn) );
|
|
if (gdds) {
|
|
return S_cas_noConvert;
|
|
}
|
|
|
|
this->pValue = pNewValue;
|
|
|
|
return S_casApp_success;
|
|
}
|
|
|
|
//
|
|
// exVecDestructor::run()
|
|
//
|
|
// special gddDestructor guarantees same form of new and delete
|
|
//
|
|
void exVecDestructor::run (void *pUntyped)
|
|
{
|
|
aitFloat32 *pf = (aitFloat32 *) pUntyped;
|
|
delete [] pf;
|
|
}
|