Moved CA client examples into their own caClientApp

Added caServerApp - copied from src/cas/example/simple
Made simpleApp significantly more useful
Made exampleApp use the _APPNAME_ macro instead of example in various places
This commit is contained in:
Andrew Johnson
2003-02-05 23:46:23 +00:00
parent 168c9c5503
commit 081cb42dc8
25 changed files with 3122 additions and 107 deletions
+23 -4
View File
@@ -24,12 +24,10 @@ TEMPLATES += top/exampleApp/src/Makefile
TEMPLATES += top/exampleApp/src/base.dbd
TEMPLATES += top/exampleApp/src/devXxxSoft.c
TEMPLATES += top/exampleApp/src/xxxRecord.c
TEMPLATES += top/exampleApp/src/caExample.c
TEMPLATES += top/exampleApp/src/caMonitor.c
TEMPLATES += top/exampleApp/src/exampleInclude.dbd
TEMPLATES += top/exampleApp/src/_APPNAME_Include.dbd
TEMPLATES += top/exampleApp/src/sncExample.stt
TEMPLATES += top/exampleApp/src/xxxRecord.dbd
TEMPLATES += top/exampleApp/src/exampleMain.cpp
TEMPLATES += top/exampleApp/src/_APPNAME_Main.cpp
TEMPLATES += top/exampleApp/src/dbSubExample.c
TEMPLATES += top/exampleBoot/Makefile
@@ -42,9 +40,30 @@ TEMPLATES += top/exampleBoot/ioc/st.cmd@RTEMS
TEMPLATES += top/exampleBoot/ioc/README@Common
TEMPLATES += top/exampleBoot/ioc/README@vxWorks
TEMPLATES += top/caClientApp/Makefile
TEMPLATES += top/caClientApp/caExample.c
TEMPLATES += top/caClientApp/caMonitor.c
TEMPLATES += top/caServerApp/Makefile
TEMPLATES += top/caServerApp/README
TEMPLATES += top/caServerApp/exAsyncPV.cc
TEMPLATES += top/caServerApp/exChannel.cc
TEMPLATES += top/caServerApp/exPV.cc
TEMPLATES += top/caServerApp/exScalarPV.cc
TEMPLATES += top/caServerApp/exServer.cc
TEMPLATES += top/caServerApp/exServer.h
TEMPLATES += top/caServerApp/exVectorPV.cc
TEMPLATES += top/caServerApp/main.cc
TEMPLATES += top/caServerApp/test.adl
TEMPLATES += top/caServerApp/vxEntry.cc
TEMPLATES += top/simpleApp/Makefile
TEMPLATES += top/simpleApp/Db/Makefile
TEMPLATES += top/simpleApp/src/Makefile
TEMPLATES += top/simpleApp/src/Makefile
TEMPLATES += top/simpleApp/src/_APPNAME_Include.dbd
TEMPLATES += top/simpleApp/src/_APPNAME_Main.cpp
TEMPLATES += top/simpleApp/src/base.dbd
TEMPLATES += top/simpleBoot/Makefile
TEMPLATES += top/simpleBoot/nfsCommands@vxWorks
+24
View File
@@ -0,0 +1,24 @@
TOP=..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================
PROD_HOST += caExample
caExample_SRCS += caExample.c
caExample_LIBS += ca
caExample_LIBS += Com
PROD_HOST += caMonitor
caMonitor_SRCS += caMonitor.c
caMonitor_LIBS += ca
caMonitor_LIBS += Com
ca_DIR = $(EPICS_BASE_LIB)
Com_DIR = $(EPICS_BASE_LIB)
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE
@@ -6,7 +6,7 @@
#include "cadef.h"
int main(int argc,char **argv)
main(int argc,char **argv)
{
double data;
chid mychid;
+38
View File
@@ -0,0 +1,38 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# 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.
#*************************************************************************
TOP=..
include $(TOP)/configure/CONFIG
PROD_LIBS := cas ca gdd Com
cas_DIR = $(INSTALL_LIB)
ca_DIR = $(INSTALL_LIB)
gdd_DIR = $(INSTALL_LIB)
Com_DIR = $(INSTALL_LIB)
#
# Added ws2_32 winmm user32 for the non-dll build
#
SYS_PROD_LIBS_WIN32 := ws2_32 advapi32 user32
SRCS += main.cc
SRCS += exServer.cc
SRCS += exPV.cc
SRCS += exVectorPV.cc
SRCS += exScalarPV.cc
SRCS += exAsyncPV.cc
SRCS += exChannel.cc
PROD_HOST = excas
include $(TOP)/configure/RULES
+11
View File
@@ -0,0 +1,11 @@
The files in this directory build an example ca server. The example
server exports 4 process variables (PVs): "fred", "freddy", "jane", and
"janet". "fred" and "jane" are synchronous PVs. "freddy" and "janet"
are asynchronous. Many ca servers will find that synchronous variables
will meet there needs and therefore will not require the increased
complexity associated with asynchronous PVs. The PVs in the example
server are updated periodically. Some random "noise" is added to each
PVs current value each time that it is updated.
The example server does not so far implement enumerated data types.
@@ -0,0 +1,140 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* 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.
\*************************************************************************/
//
// Example EPICS CA server
// (asynchrronous process variable)
//
#include "exServer.h"
//
// exAsyncPV::read()
// (virtual replacement for the default)
//
caStatus exAsyncPV::read (const casCtx &ctx, gdd &valueIn)
{
exAsyncReadIO *pIO;
if (this->simultAsychIOCount>=maxSimultAsyncIO) {
return S_casApp_postponeAsyncIO;
}
this->simultAsychIOCount++;
pIO = new exAsyncReadIO ( ctx, *this, valueIn );
if (!pIO) {
return S_casApp_noMemory;
}
return S_casApp_asyncCompletion;
}
//
// exAsyncPV::write()
// (virtual replacement for the default)
//
caStatus exAsyncPV::write ( const casCtx &ctx, const gdd &valueIn )
{
exAsyncWriteIO *pIO;
if ( this->simultAsychIOCount >= maxSimultAsyncIO ) {
return S_casApp_postponeAsyncIO;
}
this->simultAsychIOCount++;
pIO = new exAsyncWriteIO ( ctx, *this, valueIn );
if ( ! pIO ) {
return S_casApp_noMemory;
}
return S_casApp_asyncCompletion;
}
//
// exAsyncWriteIO::exAsyncWriteIO()
//
exAsyncWriteIO::exAsyncWriteIO ( const casCtx &ctxIn, exAsyncPV &pvIn,
const gdd &valueIn ) :
casAsyncWriteIO ( ctxIn ), pv ( pvIn ),
timer ( pvIn.getCAS()->createTimer () ), pValue(valueIn)
{
this->timer.start ( *this, 0.1 );
}
//
// exAsyncWriteIO::~exAsyncWriteIO()
//
exAsyncWriteIO::~exAsyncWriteIO()
{
this->pv.removeIO();
if ( this->pv.getCAS() ) {
this->timer.destroy ();
}
}
//
// exAsyncWriteIO::expire()
// (a virtual function that runs when the base timer expires)
//
epicsTimerNotify::expireStatus exAsyncWriteIO::expire ( const epicsTime & /* currentTime */ )
{
caStatus status;
status = this->pv.update ( this->pValue );
this->postIOCompletion ( status );
return noRestart;
}
//
// exAsyncReadIO::exAsyncReadIO()
//
exAsyncReadIO::exAsyncReadIO ( const casCtx &ctxIn, exAsyncPV &pvIn,
gdd &protoIn ) :
casAsyncReadIO ( ctxIn ), pv ( pvIn ),
timer ( pvIn.getCAS()->createTimer() ), pProto ( protoIn )
{
this->timer.start ( *this, 0.1 );
}
//
// exAsyncReadIO::~exAsyncReadIO()
//
exAsyncReadIO::~exAsyncReadIO()
{
this->pv.removeIO ();
if ( this->pv.getCAS() ) {
this->timer.destroy ();
}
}
//
// exAsyncReadIO::expire()
// (a virtual function that runs when the base timer expires)
//
epicsTimerNotify::expireStatus exAsyncReadIO::expire ( const epicsTime & /* currentTime */ )
{
caStatus status;
//
// map between the prototype in and the
// current value
//
status = this->pv.exPV::readNoCtx ( this->pProto );
//
// post IO completion
//
this->postIOCompletion ( status, *this->pProto );
return noRestart;
}
@@ -0,0 +1,41 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* 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.
\*************************************************************************/
//
// Example EPICS CA server
//
#include "exServer.h"
//
// exChannel::setOwner ()
//
void exChannel::setOwner(const char * const /* pUserName */,
const char * const /* pHostName */)
{
}
//
// exChannel::readAccess ()
//
bool exChannel::readAccess () const
{
return true;
}
//
// exChannel::writeAccess ()
//
bool exChannel::writeAccess () const
{
return true;
}
+348
View File
@@ -0,0 +1,348 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* 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.
\*************************************************************************/
//
// Example EPICS CA server
//
#include "exServer.h"
#include "gddApps.h"
//
// static data for exPV
//
char exPV::hasBeenInitialized = 0;
gddAppFuncTable<exPV> exPV::ft;
epicsTime exPV::currentTime;
//
// special gddDestructor guarantees same form of new and delete
//
class exFixedStringDestructor: public gddDestructor {
virtual void run (void *);
};
//
// exPV::exPV()
//
exPV::exPV ( pvInfo &setup, bool preCreateFlag, bool scanOnIn ) :
timer ( this->getCAS()->createTimer() ),
info ( setup ),
interest ( false ),
preCreate ( preCreateFlag ),
scanOn ( scanOnIn )
{
//
// no dataless PV allowed
//
assert (this->info.getElementCount()>=1u);
//
// start a very slow background scan
// (we will speed this up to the normal rate when
// someone is watching the PV)
//
if ( this->scanOn && this->info.getScanPeriod () > 0.0 ) {
this->timer.start ( *this, this->getScanPeriod() );
}
}
//
// exPV::~exPV()
//
exPV::~exPV()
{
this->timer.destroy ();
this->info.unlinkPV();
}
//
// exPV::destroy()
//
// this is replaced by a noop since we are
// pre-creating most of the PVs during init in this simple server
//
void exPV::destroy()
{
if ( ! this->preCreate ) {
delete this;
}
}
//
// exPV::update()
//
caStatus exPV::update(smartConstGDDPointer pValueIn)
{
caServer *pCAS = this->getCAS();
caStatus cas;
# if DEBUG
printf("Setting %s too:\n", this->info.getName().string());
valueIn.dump();
# endif
cas = this->updateValue (pValueIn);
if ( cas || ( ! this->pValue.valid() ) ) {
return cas;
}
//
// post a value change event
//
if (this->interest==true && pCAS!=NULL) {
casEventMask select(pCAS->valueEventMask()|pCAS->logEventMask());
this->postEvent (select, *this->pValue);
}
return S_casApp_success;
}
//
// exScanTimer::expire ()
//
epicsTimerNotify::expireStatus
exPV::expire ( const epicsTime & /*currentTime*/ ) // X aCC 361
{
this->scan();
if ( this->scanOn && this->getScanPeriod() > 0.0 ) {
return expireStatus ( restart, this->getScanPeriod() );
}
else {
return noRestart;
}
}
//
// exPV::bestExternalType()
//
aitEnum exPV::bestExternalType () const
{
return this->info.getType ();
}
//
// exPV::interestRegister()
//
caStatus exPV::interestRegister()
{
caServer *pCAS = this->getCAS();
if ( ! pCAS ) {
return S_casApp_success;
}
this->interest = true;
if ( this->scanOn && this->getScanPeriod() > 0.0 &&
this->getScanPeriod() < this->timer.getExpireDelay() ) {
this->timer.start ( *this, this->getScanPeriod() );
}
return S_casApp_success;
}
//
// exPV::interestDelete()
//
void exPV::interestDelete()
{
this->interest = false;
}
//
// exPV::show()
//
void exPV::show ( unsigned level ) const
{
if (level>1u) {
if ( this->pValue.valid () ) {
printf ( "exPV: cond=%d\n", this->pValue->getStat () );
printf ( "exPV: sevr=%d\n", this->pValue->getSevr () );
printf ( "exPV: value=%f\n", static_cast < double > ( * this->pValue ) );
}
printf ( "exPV: interest=%d\n", this->interest );
this->timer.show ( level - 1u );
}
}
//
// exPV::initFT()
//
void exPV::initFT()
{
if ( exPV::hasBeenInitialized ) {
return;
}
//
// time stamp, status, and severity are extracted from the
// GDD associated with the "value" application type.
//
exPV::ft.installReadFunc ("value", &exPV::getValue);
exPV::ft.installReadFunc ("precision", &exPV::getPrecision);
exPV::ft.installReadFunc ("graphicHigh", &exPV::getHighLimit);
exPV::ft.installReadFunc ("graphicLow", &exPV::getLowLimit);
exPV::ft.installReadFunc ("controlHigh", &exPV::getHighLimit);
exPV::ft.installReadFunc ("controlLow", &exPV::getLowLimit);
exPV::ft.installReadFunc ("alarmHigh", &exPV::getHighLimit);
exPV::ft.installReadFunc ("alarmLow", &exPV::getLowLimit);
exPV::ft.installReadFunc ("alarmHighWarning", &exPV::getHighLimit);
exPV::ft.installReadFunc ("alarmLowWarning", &exPV::getLowLimit);
exPV::ft.installReadFunc ("units", &exPV::getUnits);
exPV::ft.installReadFunc ("enums", &exPV::getEnums);
exPV::hasBeenInitialized = 1;
}
//
// exPV::getPrecision()
//
caStatus exPV::getPrecision(gdd &prec)
{
prec.put(4u);
return S_cas_success;
}
//
// exPV::getHighLimit()
//
caStatus exPV::getHighLimit(gdd &value)
{
value.put(info.getHopr());
return S_cas_success;
}
//
// exPV::getLowLimit()
//
caStatus exPV::getLowLimit(gdd &value)
{
value.put(info.getLopr());
return S_cas_success;
}
//
// exPV::getUnits()
//
caStatus exPV::getUnits(gdd &units)
{
aitString str("furlongs", aitStrRefConstImortal);
units.put(str);
return S_cas_success;
}
//
// exPV::getEnums()
//
// returns the eneumerated state strings
// for a discrete channel
//
// The PVs in this example are purely analog,
// and therefore this isnt appropriate in an
// analog context ...
//
caStatus exPV::getEnums ( gdd & enumsIn )
{
if ( this->info.getType () == aitEnumEnum16 ) {
static const unsigned nStr = 2;
aitFixedString *str;
exFixedStringDestructor *pDes;
str = new aitFixedString[nStr];
if (!str) {
return S_casApp_noMemory;
}
pDes = new exFixedStringDestructor;
if (!pDes) {
delete [] str;
return S_casApp_noMemory;
}
strncpy (str[0].fixed_string, "off",
sizeof(str[0].fixed_string));
strncpy (str[1].fixed_string, "on",
sizeof(str[1].fixed_string));
enumsIn.setDimension(1);
enumsIn.setBound (0,0,nStr);
enumsIn.putRef (str, pDes);
return S_cas_success;
}
return S_cas_success;
}
//
// exPV::getValue()
//
caStatus exPV::getValue(gdd &value)
{
caStatus status;
if ( this->pValue.valid () ) {
gddStatus gdds;
gdds = gddApplicationTypeTable::
app_table.smartCopy ( &value, & (*this->pValue) );
if (gdds) {
status = S_cas_noConvert;
}
else {
status = S_cas_success;
}
}
else {
status = S_casApp_undefined;
}
return status;
}
//
// exPV::write()
// (synchronous default)
//
caStatus exPV::write (const casCtx &, const gdd &valueIn)
{
return this->update (valueIn);
}
//
// exPV::read()
// (synchronous default)
//
caStatus exPV::read (const casCtx &, gdd &protoIn)
{
return this->ft.read (*this, protoIn);
}
//
// exPV::createChannel()
//
// for access control - optional
//
casChannel *exPV::createChannel (const casCtx &ctx,
const char * const /* pUserName */,
const char * const /* pHostName */)
{
return new exChannel (ctx);
}
//
// exFixedStringDestructor::run()
//
// special gddDestructor guarantees same form of new and delete
//
void exFixedStringDestructor::run (void *pUntyped)
{
aitFixedString *ps = (aitFixedString *) pUntyped;
delete [] ps;
}
@@ -0,0 +1,116 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* 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.
\*************************************************************************/
#include <math.h>
#include <limits.h>
#include <stdlib.h>
#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
//
// exScalarPV::scan
//
void exScalarPV::scan()
{
caStatus status;
double radians;
smartGDDPointer pDD;
float newValue;
float limit;
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 gddScalar (gddAppType_value, aitEnumFloat64);
if ( ! pDD.valid () ) {
return;
}
//
// smart pointer class manages reference count after this point
//
gddStatus = pDD->unreference();
assert (!gddStatus);
radians = (rand () * 2.0 * myPI)/RAND_MAX;
if ( this->pValue.valid () ) {
this->pValue->getConvert(newValue);
}
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);
*pDD = newValue;
aitTimeStamp gddts = this->currentTime;
pDD->setTimeStamp (&gddts);
status = this->update (pDD);
if (status!=S_casApp_success) {
errMessage (status, "scalar scan update failed\n");
}
}
//
// 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 each value change events retaining an
// independent value on the event queue.
//
caStatus exScalarPV::updateValue (smartConstGDDPointer pValueIn)
{
if ( ! pValueIn.valid () ) {
return S_casApp_undefined;
}
//
// Really no need to perform this check since the
// server lib verifies that all requests are in range
//
if (!pValueIn->isScalar()) {
return S_casApp_outOfBounds;
}
this->pValue = pValueIn;
return S_casApp_success;
}
+384
View File
@@ -0,0 +1,384 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* 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.
\*************************************************************************/
//
// fileDescriptorManager.process(delay);
// (the name of the global symbol has leaked in here)
//
//
// Example EPICS CA server
//
#include "exServer.h"
//
// static list of pre-created PVs
//
pvInfo exServer::pvList[] = {
pvInfo (1.0e-1, "jane", 10.0f, 0.0f, aitEnumFloat64, excasIoSync, 1u),
pvInfo (2.0, "fred", 10.0f, -10.0f, aitEnumFloat64, excasIoSync, 1u),
pvInfo (1.0e-1, "janet", 10.0f, 0.0f, aitEnumFloat64, excasIoAsync, 1u),
pvInfo (2.0, "freddy", 10.0f, -10.0f, aitEnumFloat64, excasIoAsync, 1u),
pvInfo (2.0, "alan", 10.0f, -10.0f, aitEnumFloat64, excasIoSync, 100u),
pvInfo (20.0, "albert", 10.0f, -10.0f, aitEnumFloat64, excasIoSync, 1000u),
pvInfo (-1.0, "boot", 10.0f, -10.0f, aitEnumEnum16, excasIoSync, 1u),
pvInfo (-1.0, "booty", 10.0f, -10.0f, aitEnumEnum16, excasIoAsync, 1u),
pvInfo (-1.0, "bill", 10.0f, -10.0f, aitEnumFloat64, excasIoSync, 1u)
};
const unsigned exServer::pvListNElem = NELEMENTS (exServer::pvList);
//
// static on-the-fly PVs
//
pvInfo exServer::billy (-1.0, "billy", 10.0f, -10.0f, aitEnumFloat64, excasIoAsync, 1u);
pvInfo exServer::bloaty (-1.0, "bloaty", 10.0f, -10.0f, aitEnumFloat64, excasIoSync, 100000u);
//
// exServer::exServer()
//
exServer::exServer ( const char * const pvPrefix,
unsigned aliasCount, bool scanOnIn ) :
simultAsychIOCount (0u),
scanOn (scanOnIn)
{
unsigned i;
exPV *pPV;
pvInfo *pPVI;
pvInfo *pPVAfter = &exServer::pvList[pvListNElem];
char pvAlias[256];
const char * const pNameFmtStr = "%.100s%.20s";
const char * const pAliasFmtStr = "%.100s%.20s%u";
exPV::initFT();
//
// pre-create all of the simple PVs that this server will export
//
for (pPVI = exServer::pvList; pPVI < pPVAfter; pPVI++) {
pPV = pPVI->createPV (*this, true, scanOnIn);
if (!pPV) {
fprintf(stderr, "Unable to create new PV \"%s\"\n",
pPVI->getName());
}
//
// Install canonical (root) name
//
sprintf(pvAlias, pNameFmtStr, pvPrefix, pPVI->getName());
this->installAliasName(*pPVI, pvAlias);
//
// Install numbered alias names
//
for (i=0u; i<aliasCount; i++) {
sprintf(pvAlias, pAliasFmtStr, pvPrefix,
pPVI->getName(), i);
this->installAliasName(*pPVI, pvAlias);
}
}
//
// Install create on-the-fly PVs
// into the PV name hash table
//
sprintf ( pvAlias, pNameFmtStr, pvPrefix, billy.getName() );
this->installAliasName ( billy, pvAlias );
sprintf ( pvAlias, pNameFmtStr, pvPrefix, bloaty.getName() );
this->installAliasName ( bloaty, pvAlias );
}
//
// exServer::~exServer()
//
exServer::~exServer()
{
pvInfo *pPVI;
pvInfo *pPVAfter =
&exServer::pvList[NELEMENTS(exServer::pvList)];
//
// delete all pre-created PVs (eliminate bounds-checker warnings)
//
for (pPVI = exServer::pvList; pPVI < pPVAfter; pPVI++) {
pPVI->deletePV ();
}
this->stringResTbl.traverse ( &pvEntry::destroy );
}
//
// exServer::installAliasName()
//
void exServer::installAliasName(pvInfo &info, const char *pAliasName)
{
pvEntry *pEntry;
pEntry = new pvEntry(info, *this, pAliasName);
if (pEntry) {
int resLibStatus;
resLibStatus = this->stringResTbl.add(*pEntry);
if (resLibStatus==0) {
return;
}
else {
delete pEntry;
}
}
fprintf ( stderr,
"Unable to enter PV=\"%s\" Alias=\"%s\" in PV name alias hash table\n",
info.getName(), pAliasName );
}
//
// exServer::pvExistTest()
//
pvExistReturn exServer::pvExistTest // X aCC 361
( const casCtx& ctxIn, const char * pPVName )
{
//
// lifetime of id is shorter than lifetime of pName
//
stringId id ( pPVName, stringId::refString );
pvEntry *pPVE;
//
// Look in hash table for PV name (or PV alias name)
//
pPVE = this->stringResTbl.lookup ( id );
if ( ! pPVE ) {
return pverDoesNotExistHere;
}
pvInfo & pvi = pPVE->getInfo();
//
// Initiate async IO if this is an async PV
//
if ( pvi.getIOType() == excasIoSync ) {
return pverExistsHere;
}
else {
if ( this->simultAsychIOCount >= maxSimultAsyncIO ) {
return pverDoesNotExistHere;
}
this->simultAsychIOCount++;
exAsyncExistIO *pIO;
pIO = new exAsyncExistIO ( pvi, ctxIn, *this );
if (pIO) {
return pverAsyncCompletion;
}
else {
return pverDoesNotExistHere;
}
}
}
//
// exServer::pvAttach()
//
pvAttachReturn exServer::pvAttach // X aCC 361
(const casCtx &ctx, const char *pName)
{
//
// lifetime of id is shorter than lifetime of pName
//
stringId id(pName, stringId::refString);
exPV *pPV;
pvEntry *pPVE;
pPVE = this->stringResTbl.lookup(id);
if (!pPVE) {
return S_casApp_pvNotFound;
}
pvInfo &pvi = pPVE->getInfo();
//
// If this is a synchronous PV create the PV now
//
if (pvi.getIOType() == excasIoSync) {
pPV = pvi.createPV(*this, false, this->scanOn);
if (pPV) {
return *pPV;
}
else {
return S_casApp_noMemory;
}
}
//
// Initiate async IO if this is an async PV
//
else {
if (this->simultAsychIOCount>=maxSimultAsyncIO) {
return S_casApp_postponeAsyncIO;
}
this->simultAsychIOCount++;
exAsyncCreateIO *pIO =
new exAsyncCreateIO(pvi, *this, ctx, this->scanOn);
if (pIO) {
return S_casApp_asyncCompletion;
}
else {
return S_casApp_noMemory;
}
}
}
//
// pvInfo::createPV()
//
exPV *pvInfo::createPV ( exServer & /*cas*/,
bool preCreateFlag, bool scanOn )
{
if (this->pPV) {
return this->pPV;
}
exPV *pNewPV;
//
// create an instance of the appropriate class
// depending on the io type and the number
// of elements
//
if (this->elementCount==1u) {
switch (this->ioType){
case excasIoSync:
pNewPV = new exScalarPV ( *this, preCreateFlag, scanOn );
break;
case excasIoAsync:
pNewPV = new exAsyncPV ( *this, preCreateFlag, scanOn );
break;
default:
pNewPV = NULL;
break;
}
}
else {
if ( this->ioType == excasIoSync ) {
pNewPV = new exVectorPV ( *this, preCreateFlag, scanOn );
}
else {
pNewPV = NULL;
}
}
//
// load initial value (this is not done in
// the constructor because the base class's
// pure virtual function would be called)
//
// We always perform this step even if
// scanning is disable so that there will
// always be an initial value
//
if (pNewPV) {
this->pPV = pNewPV;
pNewPV->scan();
}
return pNewPV;
}
//
// exServer::show()
//
void exServer::show (unsigned level) const
{
//
// server tool specific show code goes here
//
this->stringResTbl.show(level);
//
// print information about ca server libarary
// internals
//
this->caServer::show(level);
}
//
// exAsyncExistIO::exAsyncExistIO()
//
exAsyncExistIO::exAsyncExistIO ( const pvInfo &pviIn, const casCtx &ctxIn,
exServer &casIn ) :
casAsyncPVExistIO ( ctxIn ), pvi ( pviIn ),
timer ( casIn.createTimer () ), cas ( casIn )
{
this->timer.start ( *this, 0.00001 );
}
//
// exAsyncExistIO::~exAsyncExistIO()
//
exAsyncExistIO::~exAsyncExistIO()
{
this->cas.removeIO ();
this->timer.destroy ();
}
//
// exAsyncExistIO::expire()
// (a virtual function that runs when the base timer expires)
//
epicsTimerNotify::expireStatus exAsyncExistIO::expire ( const epicsTime & /*currentTime*/ )
{
//
// post IO completion
//
this->postIOCompletion ( pvExistReturn(pverExistsHere) );
return noRestart;
}
//
// exAsyncCreateIO::exAsyncCreateIO()
//
exAsyncCreateIO::exAsyncCreateIO ( pvInfo &pviIn, exServer &casIn,
const casCtx &ctxIn, bool scanOnIn ) :
casAsyncPVAttachIO ( ctxIn ), pvi ( pviIn ),
timer ( casIn.createTimer () ),
cas ( casIn ), scanOn ( scanOnIn )
{
this->timer.start ( *this, 0.00001 );
}
//
// exAsyncCreateIO::~exAsyncCreateIO()
//
exAsyncCreateIO::~exAsyncCreateIO()
{
this->cas.removeIO ();
this->timer.destroy ();
}
//
// exAsyncCreateIO::expire()
// (a virtual function that runs when the base timer expires)
//
epicsTimerNotify::expireStatus exAsyncCreateIO::expire ( const epicsTime & /*currentTime*/ )
{
exPV *pPV;
pPV = this->pvi.createPV ( this->cas, false, this->scanOn );
if ( pPV ) {
this->postIOCompletion ( pvAttachReturn ( *pPV ) );
}
else {
this->postIOCompletion ( pvAttachReturn ( S_casApp_noMemory ) );
}
return noRestart;
}
+543
View File
@@ -0,0 +1,543 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* 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.
\*************************************************************************/
//
// Example EPICS CA server
//
//
// caServer
// |
// exServer
//
// casPV
// |
// exPV-----------
// | |
// exScalarPV exVectorPV
// |
// exAsyncPV
//
// casChannel
// |
// exChannel
//
//
// ANSI C
//
#include <string.h>
#include <stdio.h>
//
// EPICS
//
#include "gddAppFuncTable.h"
#include "epicsTimer.h"
#include "casdef.h"
#include "epicsAssert.h"
#include "resourceLib.h"
#include "tsMinMax.h"
#ifndef NELEMENTS
# define NELEMENTS(A) (sizeof(A)/sizeof(A[0]))
#endif
#define maxSimultAsyncIO 1000u
//
// info about all pv in this server
//
enum excasIoType { excasIoSync, excasIoAsync };
class exPV;
class exServer;
//
// pvInfo
//
class pvInfo {
public:
pvInfo ( double scanPeriodIn, const char *pNameIn,
aitFloat32 hoprIn, aitFloat32 loprIn,
aitEnum typeIn, excasIoType ioTypeIn,
unsigned countIn );
pvInfo ( const pvInfo & copyIn );
~pvInfo ();
double getScanPeriod () const;
const char *getName () const;
double getHopr () const;
double getLopr () const;
aitEnum getType () const;
excasIoType getIOType () const;
unsigned getElementCount () const;
void unlinkPV ();
exPV *createPV ( exServer & exCAS,
bool preCreateFlag, bool scanOn );
void deletePV ();
private:
const double scanPeriod;
const char * pName;
const double hopr;
const double lopr;
aitEnum type;
const excasIoType ioType;
const unsigned elementCount;
exPV * pPV;
};
//
// pvEntry
//
// o entry in the string hash table for the pvInfo
// o Since there may be aliases then we may end up
// with several of this class all referencing
// the same pv info class (justification
// for this breaking out into a seperate class
// from pvInfo)
//
class pvEntry // X aCC 655
: public stringId, public tsSLNode < pvEntry > {
public:
pvEntry ( pvInfo &infoIn, exServer & casIn,
const char * pAliasName );
~pvEntry();
pvInfo & getInfo() const { return this->info; }
void destroy ();
private:
pvInfo & info;
exServer & cas;
};
//
// exPV
//
class exPV : public casPV, public epicsTimerNotify,
public tsSLNode < exPV > {
public:
exPV ( pvInfo & setup, bool preCreateFlag, bool scanOn );
virtual ~exPV();
void show ( unsigned level ) const;
//
// Called by the server libary each time that it wishes to
// subscribe for PV the server tool via postEvent() below.
//
caStatus interestRegister ();
//
// called by the server library each time that it wishes to
// remove its subscription for PV value change events
// from the server tool via caServerPostEvents()
//
void interestDelete ();
aitEnum bestExternalType () const;
//
// chCreate() is called each time that a PV is attached to
// by a client. The server tool must create a casChannel object
// (or a derived class) each time that this routine is called
//
// If the operation must complete asynchronously then return
// the status code S_casApp_asyncCompletion and then
// create the casChannel object at some time in the future
//
//casChannel *createChannel ();
//
// This gets called when the pv gets a new value
//
caStatus update ( smartConstGDDPointer pValue );
//
// Gets called when we add noise to the current value
//
virtual void scan () = 0;
//
// If no one is watching scan the PV with 10.0
// times the specified period
//
double getScanPeriod ();
caStatus read ( const casCtx &, gdd & protoIn );
caStatus readNoCtx ( smartGDDPointer pProtoIn );
caStatus write ( const casCtx &, const gdd & value );
void destroy ();
const pvInfo & getPVInfo ();
const char * getName() const;
static void initFT();
casChannel * createChannel ( const casCtx &ctx,
const char * const pUserName,
const char * const pHostName );
protected:
smartConstGDDPointer pValue;
epicsTimer & timer;
pvInfo & info;
bool interest;
bool preCreate;
bool scanOn;
static epicsTime currentTime;
virtual caStatus updateValue ( smartConstGDDPointer pValue ) = 0;
private:
//
// scan timer expire
//
expireStatus expire ( const epicsTime & currentTime );
//
// Std PV Attribute fetch support
//
gddAppFuncTableStatus getPrecision(gdd &value);
gddAppFuncTableStatus getHighLimit(gdd &value);
gddAppFuncTableStatus getLowLimit(gdd &value);
gddAppFuncTableStatus getUnits(gdd &value);
gddAppFuncTableStatus getValue(gdd &value);
gddAppFuncTableStatus getEnums(gdd &value);
//
// static
//
static gddAppFuncTable<exPV> ft;
static char hasBeenInitialized;
};
//
// exScalarPV
//
class exScalarPV : public exPV {
public:
exScalarPV ( pvInfo &setup, bool preCreateFlag, bool scanOnIn ) :
exPV ( setup, preCreateFlag, scanOnIn) {}
void scan();
private:
caStatus updateValue (smartConstGDDPointer pValue);
};
//
// exVectorPV
//
class exVectorPV : public exPV {
public:
exVectorPV ( pvInfo &setup, bool preCreateFlag, bool scanOnIn ) :
exPV ( setup, preCreateFlag, scanOnIn) {}
void scan();
unsigned maxDimension() const;
aitIndex maxBound (unsigned dimension) const;
private:
caStatus updateValue (smartConstGDDPointer pValue);
};
//
// exServer
//
class exServer : public caServer {
public:
exServer ( const char * const pvPrefix,
unsigned aliasCount, bool scanOn );
~exServer ();
void show ( unsigned level ) const;
pvExistReturn pvExistTest ( const casCtx &, const char * pPVName );
pvAttachReturn pvAttach ( const casCtx &, const char * pPVName );
void installAliasName ( pvInfo & info, const char * pAliasName );
inline void removeAliasName ( pvEntry & entry );
void removeIO();
private:
resTable < pvEntry, stringId > stringResTbl;
unsigned simultAsychIOCount;
bool scanOn;
//
// list of pre-created PVs
//
static pvInfo pvList[];
static const unsigned pvListNElem;
//
// on-the-fly PVs
//
static pvInfo bill;
static pvInfo billy;
static pvInfo bloaty;
static pvInfo boot;
static pvInfo booty;
};
//
// exAsyncPV
//
class exAsyncPV : public exScalarPV {
public:
exAsyncPV ( pvInfo &setup, bool preCreateFlag, bool scanOnIn );
caStatus read ( const casCtx & ctxIn, gdd & protoIn );
caStatus write ( const casCtx & ctxIn, const gdd & value );
void removeIO();
private:
unsigned simultAsychIOCount;
};
//
// exChannel
//
class exChannel : public casChannel{
public:
exChannel ( const casCtx & ctxIn );
void setOwner ( const char * const pUserName,
const char * const pHostName );
bool readAccess () const;
bool writeAccess () const;
private:
};
//
// exAsyncWriteIO
//
class exAsyncWriteIO : public casAsyncWriteIO, public epicsTimerNotify {
public:
exAsyncWriteIO ( const casCtx & ctxIn, exAsyncPV & pvIn, const gdd & valueIn );
~exAsyncWriteIO ();
private:
exAsyncPV & pv;
epicsTimer & timer;
smartConstGDDPointer pValue;
expireStatus expire ( const epicsTime & currentTime );
};
//
// exAsyncReadIO
//
class exAsyncReadIO : public casAsyncReadIO, public epicsTimerNotify {
public:
exAsyncReadIO ( const casCtx & ctxIn, exAsyncPV & pvIn, gdd & protoIn );
virtual ~exAsyncReadIO ();
private:
exAsyncPV & pv;
epicsTimer & timer;
smartGDDPointer pProto;
expireStatus expire ( const epicsTime & currentTime );
};
//
// exAsyncExistIO
// (PV exist async IO)
//
class exAsyncExistIO : public casAsyncPVExistIO, public epicsTimerNotify {
public:
exAsyncExistIO ( const pvInfo & pviIn, const casCtx & ctxIn,
exServer & casIn );
virtual ~exAsyncExistIO ();
private:
const pvInfo & pvi;
epicsTimer & timer;
exServer & cas;
expireStatus expire ( const epicsTime & currentTime );
};
//
// exAsyncCreateIO
// (PV create async IO)
//
class exAsyncCreateIO : public casAsyncPVAttachIO, public epicsTimerNotify {
public:
exAsyncCreateIO ( pvInfo & pviIn, exServer & casIn,
const casCtx & ctxIn, bool scanOnIn );
virtual ~exAsyncCreateIO ();
private:
pvInfo & pvi;
epicsTimer & timer;
exServer & cas;
bool scanOn;
expireStatus expire ( const epicsTime & currentTime );
};
inline pvInfo::pvInfo ( double scanPeriodIn, const char *pNameIn,
aitFloat32 hoprIn, aitFloat32 loprIn,
aitEnum typeIn, excasIoType ioTypeIn,
unsigned countIn ) :
scanPeriod ( scanPeriodIn ), pName ( pNameIn ),
hopr ( hoprIn ), lopr ( loprIn ), type ( typeIn ),
ioType ( ioTypeIn ), elementCount ( countIn ),
pPV ( 0 )
{
}
//
// for use when MSVC++ will not build a default copy constructor
// for this class
//
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 )
{
}
inline pvInfo::~pvInfo ()
{
//
// GDD cleanup gets rid of GDD's that are in use
// by the PV before the file scope destructer for
// this class runs here so this does not seem to
// be a good idea
//
//if ( this->pPV != NULL ) {
// delete this->pPV;
//}
}
inline void pvInfo::deletePV ()
{
if ( this->pPV != NULL ) {
delete this->pPV;
}
}
inline double pvInfo::getScanPeriod () const
{
return this->scanPeriod;
}
inline const char *pvInfo::getName () const
{
return this->pName;
}
inline double pvInfo::getHopr () const
{
return this->hopr;
}
inline double pvInfo::getLopr () const
{
return this->lopr;
}
inline aitEnum pvInfo::getType () const
{
return this->type;
}
inline excasIoType pvInfo::getIOType () const
{
return this->ioType;
}
inline unsigned pvInfo::getElementCount () const
{
return this->elementCount;
}
inline void pvInfo::unlinkPV ()
{
this->pPV = NULL;
}
inline pvEntry::pvEntry ( pvInfo & infoIn, exServer & casIn,
const char * pAliasName ) :
stringId ( pAliasName ), info ( infoIn ), cas ( casIn )
{
assert ( this->stringId::resourceName() != NULL );
}
inline pvEntry::~pvEntry ()
{
this->cas.removeAliasName ( *this );
}
inline void pvEntry::destroy ()
{
delete this;
}
inline void exServer::removeAliasName ( pvEntry & entry )
{
pvEntry * pE;
pE = this->stringResTbl.remove ( entry );
assert ( pE == &entry );
}
inline double exPV::getScanPeriod ()
{
double curPeriod = this->info.getScanPeriod ();
if ( ! this->interest ) {
curPeriod *= 10.0L;
}
return curPeriod;
}
inline caStatus exPV::readNoCtx ( smartGDDPointer pProtoIn )
{
return this->ft.read ( *this, *pProtoIn );
}
inline const pvInfo & exPV::getPVInfo ()
{
return this->info;
}
inline const char * exPV::getName () const
{
return this->info.getName();
}
inline void exServer::removeIO()
{
if ( this->simultAsychIOCount > 0u ) {
this->simultAsychIOCount--;
}
else {
fprintf ( stderr,
"simultAsychIOCount underflow?\n" );
}
}
inline exAsyncPV::exAsyncPV ( pvInfo & setup, bool preCreateFlag,
bool scanOnIn ) :
exScalarPV ( setup, preCreateFlag, scanOnIn ),
simultAsychIOCount ( 0u )
{
}
inline void exAsyncPV::removeIO ()
{
if ( this->simultAsychIOCount > 0u ) {
this->simultAsychIOCount--;
}
else {
fprintf ( stderr, "inconsistent simultAsychIOCount?\n" );
}
}
inline exChannel::exChannel ( const casCtx & ctxIn ) :
casChannel(ctxIn)
{
}
@@ -0,0 +1,274 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* 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.
\*************************************************************************/
#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;
}
+110
View File
@@ -0,0 +1,110 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* 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.
\*************************************************************************/
#include "envDefs.h"
#include "exServer.h"
#include "fdManager.h"
//
// main()
// (example single threaded ca server tool main loop)
//
extern int main (int argc, const char **argv)
{
epicsTime begin (epicsTime::getCurrent());
exServer *pCAS;
unsigned debugLevel = 0u;
double executionTime;
char pvPrefix[128] = "";
unsigned aliasCount = 1u;
unsigned scanOnAsUnsignedInt = true;
char arraySize[64] = "";
bool scanOn;
bool forever = true;
int i;
for ( i = 1; i < argc; i++ ) {
if (sscanf(argv[i], "-d %u", &debugLevel)==1) {
continue;
}
if (sscanf(argv[i],"-t %lf", &executionTime)==1) {
forever = false;
continue;
}
if (sscanf(argv[i],"-p %127s", pvPrefix)==1) {
continue;
}
if (sscanf(argv[i],"-c %u", &aliasCount)==1) {
continue;
}
if (sscanf(argv[i],"-s %u", &scanOnAsUnsignedInt)==1) {
continue;
}
if (sscanf(argv[i],"-a %63s", arraySize)==1) {
continue;
}
printf ("\"%s\"?\n", argv[i]);
printf (
"usage: %s [-d<debug level> -t<execution time> -p<PV name prefix> "
"-c<numbered alias count> -s<1=scan on (default), 0=scan off]> "
"-a<max array size>]\n",
argv[0]);
return (1);
}
if ( arraySize[0] != '\0' ) {
epicsEnvSet ( "EPICS_CA_MAX_ARRAY_BYTES", arraySize );
}
if (scanOnAsUnsignedInt) {
scanOn = true;
}
else {
scanOn = false;
}
try {
pCAS = new exServer ( pvPrefix, aliasCount, scanOn );
}
catch ( ... ) {
errlogPrintf ( "Server initialization error\n" );
errlogFlush ();
return (-1);
}
pCAS->setDebugLevel(debugLevel);
if ( forever ) {
//
// loop here forever
//
while (true) {
fileDescriptorManager.process(1000.0);
}
}
else {
double delay = epicsTime::getCurrent() - begin;
//
// loop here untill the specified execution time
// expires
//
while ( delay < executionTime ) {
fileDescriptorManager.process ( delay );
delay = epicsTime::getCurrent() - begin;
}
}
pCAS->show(2u);
delete pCAS;
errlogFlush ();
return (0);
}
+844
View File
@@ -0,0 +1,844 @@
file {
name="test.dl"
}
display {
magic="305419896"
majv="2"
mnrv="4"
ndyng="0"
npc="5"
nstr="8"
ndynamic="12"
nplot="0"
nrd="0"
nes="0"
nkd="0"
object {
x="0"
y="0"
width="421"
height="306"
}
clr="0"
bclr="1"
nwords_dspy="1106"
nwords_sta="28"
nwords_cmap="36"
nwords_crules="106"
odyng="306"
osta="278"
odynamic="306"
oplot="1106"
ord="1106"
oes="1106"
okd="1106"
opc="58"
ostr="88"
ocmap="136"
ocrules="172"
style="solid"
fill="outline"
width="0"
clrmod="static"
vismod="static"
clrrule="alarm"
pv=""
cmap=""
}
"<<color map>>" {
ncolors="8"
dl_color {
r="255"
g="255"
b="255"
inten="255"
blink="off"
RISCpad="128"
}
dl_color {
r="0"
g="0"
b="0"
inten="0"
blink="off"
RISCpad="75"
}
dl_color {
r="255"
g="0"
b="0"
inten="255"
blink="off"
RISCpad="-14684"
}
dl_color {
r="255"
g="0"
b="0"
inten="255"
blink="on"
RISCpad="14744"
}
dl_color {
r="255"
g="255"
b="0"
inten="255"
blink="off"
RISCpad="-16536"
}
dl_color {
r="255"
g="255"
b="0"
inten="255"
blink="on"
RISCpad="-15536"
}
dl_color {
r="0"
g="0"
b="255"
inten="255"
blink="off"
RISCpad="-28408"
}
dl_color {
r="0"
g="0"
b="255"
inten="255"
blink="on"
RISCpad="0"
}
}
"<<color rules>>" {
nrules="1"
dl_color_rule {
name="alarm"
info[0] {
chan="$(C).SEVR"
value="MAJOR"
connector="use"
comparator="equals"
clr="2"
RISCpad="0"
}
info[1] {
chan="$(C).SEVR"
value="MINOR"
connector="use"
comparator="equals"
clr="4"
RISCpad="127"
}
info[2] {
chan="$(C).SEVR"
value="INFO"
connector="use"
comparator="equals"
clr="6"
RISCpad="44"
}
info[3] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-128"
}
info[4] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-1"
}
info[5] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-104"
}
info[6] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-1"
}
info[7] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="8"
}
info[8] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="120"
}
info[9] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="1"
}
info[10] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="7"
}
info[11] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="19"
}
info[12] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="48"
}
info[13] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="28"
}
info[14] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="-88"
}
info[15] {
chan=""
value=""
connector="use"
comparator="equals"
clr="1"
RISCpad="0"
}
fg_enable="on"
bg_enable="on"
default_fg="0"
default_bg="1"
}
}
"<<basic attribute>>" {
attr {
clr="0"
style="solid"
fill="outline"
width="0"
}
}
"text" {
object {
x="44"
y="16"
width="104"
height="14"
groupid="0"
}
textix="Sync"
align="horiz. left"
RISC_pad="0"
}
"text" {
object {
x="260"
y="13"
width="92"
height="17"
groupid="0"
}
textix="Async"
align="horiz. left"
RISC_pad="0"
}
"indicator" {
object {
x="15"
y="88"
width="170"
height="22"
groupid="0"
}
monitor {
chan="fred"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
RISC_pad="0"
}
"text update" {
object {
x="16"
y="133"
width="169"
height="17"
groupid="0"
}
monitor {
chan="fred"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="append"
decorate="none"
convertFunc=""
convertParams=""
}
align="horiz. left"
format="decimal"
}
"valuator" {
object {
x="15"
y="43"
width="168"
height="26"
groupid="0"
}
control {
chan="fred"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
gain="coarse"
sendMode="send on motion"
increment="0"
}
"indicator" {
object {
x="215"
y="81"
width="170"
height="30"
groupid="0"
}
monitor {
chan="freddy"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
RISC_pad="0"
}
"text update" {
object {
x="216"
y="133"
width="171"
height="18"
groupid="0"
}
monitor {
chan="freddy"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="append"
decorate="none"
convertFunc=""
convertParams=""
}
align="horiz. left"
format="decimal"
}
"valuator" {
object {
x="215"
y="43"
width="168"
height="28"
groupid="0"
}
control {
chan="freddy"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
gain="coarse"
sendMode="send on motion"
increment="0"
}
"indicator" {
object {
x="16"
y="225"
width="171"
height="19"
groupid="0"
}
monitor {
chan="jane"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
RISC_pad="0"
}
"text update" {
object {
x="17"
y="259"
width="170"
height="20"
groupid="0"
}
monitor {
chan="jane"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="append"
decorate="none"
convertFunc=""
convertParams=""
}
align="horiz. left"
format="decimal"
}
"valuator" {
object {
x="15"
y="187"
width="170"
height="19"
groupid="0"
}
control {
chan="jane"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
gain="coarse"
sendMode="send on motion"
increment="0"
}
"indicator" {
object {
x="219"
y="218"
width="173"
height="23"
groupid="0"
}
monitor {
chan="janet"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
RISC_pad="0"
}
"text update" {
object {
x="220"
y="257"
width="174"
height="20"
groupid="0"
}
monitor {
chan="janet"
clr="0"
bclr="1"
label="none"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="append"
decorate="none"
convertFunc=""
convertParams=""
}
align="horiz. left"
format="decimal"
}
"valuator" {
object {
x="219"
y="188"
width="171"
height="21"
groupid="0"
}
control {
chan="janet"
clr="0"
bclr="1"
label="limits"
clrmod="static"
rulechan[0] = ""
rulechan[1] = ""
rulechan[2] = ""
rulechan[3] = ""
rulechan[4] = ""
rulechan[5] = ""
rulechan[6] = ""
rulechan[7] = ""
rulechan[8] = ""
rulechan[9] = ""
rulechan[10] = ""
rulechan[11] = ""
rulechan[12] = ""
rulechan[13] = ""
rulechan[14] = ""
rulechan[15] = ""
clrrule="alarm"
clrargs=""
rulecolorbg="0"
rulecolorfg="0"
hdl="0"
ldl="0"
prec="-1"
newunits=""
units="none"
decorate="none"
convertFunc=""
convertParams=""
}
direction="down"
gain="coarse"
sendMode="send on motion"
increment="0"
}
@@ -0,0 +1,80 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* 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.
\*************************************************************************/
//
// $Id$
// Author: Jeff HIll (LANL)
//
//
#include <vxWorks.h>
#include <taskLib.h>
#include "exServer.h"
//
// so we can call this from the vxWorks shell
//
extern "C" {
exServer *pExampleCAS;
//
// excas ()
// (vxWorks example server entry point)
//
int excas (unsigned debugLevel, unsigned delaySec)
{
epicsTime begin(epicsTime::getCurrent());
exServer *pCAS;
pCAS = new exServer(32u,5u,500u);
if (!pCAS) {
return (-1);
}
pCAS->setDebugLevel(debugLevel);
pExampleCAS = pCAS;
if (delaySec==0u) {
//
// loop here forever
//
while (1) {
taskDelay(10);
}
}
else {
epicsTime total( ((float)delaySec) );
epicsTime delay(epicsTime::getCurrent() - begin);
//
// loop here untill the specified execution time
// expires
//
while (delay < total) {
taskDelay(10);
delay = epicsTime::getCurrent() - begin;
}
}
pCAS->show(debugLevel);
pExampleCAS = NULL;
delete pCAS;
return 0;
}
int excasShow(unsigned level)
{
if (pExampleCAS!=NULL) {
pExampleCAS->show(level);
}
return 0;
}
} // extern "C"
+30 -48
View File
@@ -5,55 +5,37 @@ include $(TOP)/configure/CONFIG
# ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================
#USR_CFLAGS +=
PROD_HOST += caExample
caExample_SRCS += caExample.c
caExample_LIBS += ca
caExample_LIBS += Com
PROD_HOST += caMonitor
caMonitor_SRCS += caMonitor.c
caMonitor_LIBS += ca
caMonitor_LIBS += Com
ca_DIR = $(EPICS_BASE_LIB)
Com_DIR = $(EPICS_BASE_LIB)
#=============================
# xxxRecord.h will be created from xxxRecord.dbd
DBDINC += xxxRecord
# <name>.dbd will be created from <name>Include.dbd
DBD += example.dbd
DBD += _APPNAME_.dbd
#=============================
PROD_IOC = example
PROD_IOC = _APPNAME_
example_SRCS += xxxRecord.c
example_SRCS += devXxxSoft.c
example_SRCS += dbSubExample.c
_APPNAME__SRCS += xxxRecord.c
_APPNAME__SRCS += devXxxSoft.c
_APPNAME__SRCS += dbSubExample.c
# <name>_registerRecordDeviceDriver.cpp will be created from <name>.dbd
example_SRCS += example_registerRecordDeviceDriver.cpp
example_SRCS_DEFAULT += exampleMain.cpp
example_SRCS_vxWorks += -nil-
_APPNAME__SRCS += _APPNAME__registerRecordDeviceDriver.cpp
_APPNAME__SRCS_DEFAULT += _APPNAME_Main.cpp
_APPNAME__SRCS_vxWorks += -nil-
#The following adds support from base/src/vxWorks
example_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
_APPNAME__OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
#NOTES:
# 1)It is not possible to build sncExample both as a component of example
# 1)It is not possible to build sncExample both as a component of _APPNAME_
# and standalone. You must choose only one.
# 2)To build sncExample SNCSEQ must be defined in <top>/configure/RELEASE
#The following builds sncExample as a component of example
#example_SRCS += sncExample.stt
#example_LIBS += seq
#example_LIBS += pv
#The following builds sncExample as a component of _APPNAME_
#_APPNAME__SRCS += sncExample.stt
#_APPNAME__LIBS += seq
#_APPNAME__LIBS += pv
#seq_DIR = $(SNCSEQ_LIB)
#pv_DIR = $(SNCSEQ_LIB)
@@ -77,23 +59,23 @@ example_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
#sncExample_LIBS += Com
# Use win32 object libs for registered support
example_LIBS_win32 += recIocObj
example_LIBS_win32 += softDevIocObj
example_LIBS_win32 += testDevIocObj
example_LIBS_DEFAULT += recIoc
example_LIBS_DEFAULT += softDevIoc
example_LIBS_DEFAULT += testDevIoc
_APPNAME__LIBS_win32 += recIocObj
_APPNAME__LIBS_win32 += softDevIocObj
_APPNAME__LIBS_win32 += testDevIocObj
_APPNAME__LIBS_DEFAULT += recIoc
_APPNAME__LIBS_DEFAULT += softDevIoc
_APPNAME__LIBS_DEFAULT += testDevIoc
example_LIBS += iocsh
example_LIBS += miscIoc
example_LIBS += rsrvIoc
example_LIBS += dbtoolsIoc
example_LIBS += asIoc
example_LIBS += dbIoc
example_LIBS += registryIoc
example_LIBS += dbStaticIoc
example_LIBS += ca
example_LIBS += Com
_APPNAME__LIBS += iocsh
_APPNAME__LIBS += miscIoc
_APPNAME__LIBS += rsrvIoc
_APPNAME__LIBS += dbtoolsIoc
_APPNAME__LIBS += asIoc
_APPNAME__LIBS += dbIoc
_APPNAME__LIBS += registryIoc
_APPNAME__LIBS += dbStaticIoc
_APPNAME__LIBS += ca
_APPNAME__LIBS += Com
#===========================
@@ -5,12 +5,14 @@ typedef long (*processMethod)(subRecord *precord);
long mySubInit(subRecord *precord,processMethod process)
{
printf("%s mySubInit process %p\n",precord->name, (void*) process);
printf("Record %s called mySubInit(%#p, %#p)\n",
precord->name, precord, (void*) process);
return(0);
}
long mySubProcess(subRecord *precord)
{
printf("%s mySubProcess\n",precord->name);
printf("Record %s called mySubProcess(%#p)\n",
precord->name, precord);
return(0);
}
@@ -1,3 +1,7 @@
To start the ioc from this directory execute the command
../../bin/_ARCH_/example st.cmd
../../bin/_ARCH_/<appname> st.cmd
You may need to change the name of the .dbd file given in
st.cmd's dbLoadDatabase command before starting the ioc.
+34 -51
View File
@@ -3,73 +3,56 @@ TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================
#=======Create Host Programs=======
ca_DIR = $(EPICS_BASE_LIB)
Com_DIR = $(EPICS_BASE_LIB)
#_APPNAME_.dbd will be created from _APPNAME_Include.dbd
DBD += _APPNAME_.dbd
#USR_CFLAGS +=
#_APPNAME__registerRecordDeviceDriver.cpp will be created from _APPNAME_.dbd
_APPNAME__SRCS += _APPNAME__registerRecordDeviceDriver.cpp
# For Each Host Product define the following:1
#PROD_HOST = <product>
#<product>_SRCS += xxx.c
#...
#<product>_LIBS += ca
#<product>_LIBS += Com
#=============================
#========Database Products================
PROD_IOC = _APPNAME_
# xxxRecord.h will be created from xxxRecord.dbd
#DBDINC += xxxRecord
## Build and add other local sources like this:
#_APPNAME__SRCS += xxx.c xxx.cpp xxx.stt
#<name>.dbd will be created from <name>Include.dbd
#DBD += <name>.dbd
## If _APPNAME_ is to be built for both vxWorks and for the host then
_APPNAME__SRCS_DEFAULT += _APPNAME_Main.cpp
_APPNAME__SRCS_vxWorks += -nil-
#=======Create an IOC program=====
#PROD_IOC = <name>
#<name>_SRCS += xxx.c # .cpp .stt etc
#...
#<name>_registerRecordDeviceDriver.cpp will be created from <name>.dbd
#<name>_SRCS += <name>_registerRecordDeviceDriver.cpp
## If <name> is to be built for both vxWorks and for the host then
#<name>_SRCS_DEFAULT += <name>Main.cpp
#<name>_SRCS_vxWorks += -nil-
#The following adds support from base/src/vxWorks
#<name>_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
## The following adds support from base/src/vxWorks
_APPNAME__OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
##Define all possible libraries
## Use win32 object libs for registered support
#<name>_LIBS_win32 += recIocObj
#<name>_LIBS_win32 += softDevIocObj
#<name>_LIBS_win32 += testDevIocObj
#<name>_LIBS_DEFAULT += recIoc
#<name>_LIBS_DEFAULT += softDevIoc
#<name>_LIBS_DEFAULT += testDevIoc
_APPNAME__LIBS_win32 += recIocObj
_APPNAME__LIBS_win32 += softDevIocObj
_APPNAME__LIBS_win32 += testDevIocObj
_APPNAME__LIBS_DEFAULT += recIoc
_APPNAME__LIBS_DEFAULT += softDevIoc
_APPNAME__LIBS_DEFAULT += testDevIoc
#<name>_LIBS += iocsh
#<name>_LIBS += miscIoc
#<name>_LIBS += rsrvIoc
#<name>_LIBS += dbtoolsIoc
#<name>_LIBS += asIoc
#<name>_LIBS += dbIoc
#<name>_LIBS += registryIoc
#<name>_LIBS += dbStaticIoc
#<name>_LIBS += ca
#<name>_LIBS += Com
_APPNAME__LIBS += iocsh
_APPNAME__LIBS += miscIoc
_APPNAME__LIBS += rsrvIoc
_APPNAME__LIBS += dbtoolsIoc
_APPNAME__LIBS += asIoc
_APPNAME__LIBS += dbIoc
_APPNAME__LIBS += registryIoc
_APPNAME__LIBS += dbStaticIoc
_APPNAME__LIBS += ca
_APPNAME__LIBS += Com
## If sequence programs are being built
#<name>_LIBS += seq
#<name>_LIBS += pv
## For sequence programs, use
#_APPNAME__SRCS += sncExample.stt
#_APPNAME__LIBS += seq
#_APPNAME__LIBS += pv
#seq_DIR = $(SNCSEQ_LIB)
#pv_DIR = $(SNCSEQ_LIB)
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE
@@ -0,0 +1 @@
include "base.dbd"
@@ -0,0 +1,21 @@
/* exampleMain.c */
/* Author: Marty Kraimer Date: 17MAR2000 */
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "epicsThread.h"
#include "iocsh.h"
int main(int argc,char *argv[])
{
if(argc>=2) {
iocsh(argv[1]);
epicsThreadSleep(.2);
}
iocsh(NULL);
return(0);
}
@@ -0,0 +1,50 @@
include "menuGlobal.dbd"
include "menuConvert.dbd"
include "aiRecord.dbd"
include "aoRecord.dbd"
include "biRecord.dbd"
include "boRecord.dbd"
include "calcRecord.dbd"
include "calcoutRecord.dbd"
include "compressRecord.dbd"
include "dfanoutRecord.dbd"
include "eventRecord.dbd"
include "fanoutRecord.dbd"
include "longinRecord.dbd"
include "longoutRecord.dbd"
include "mbbiRecord.dbd"
include "mbbiDirectRecord.dbd"
include "mbboRecord.dbd"
include "mbboDirectRecord.dbd"
include "permissiveRecord.dbd"
include "selRecord.dbd"
include "seqRecord.dbd"
include "stateRecord.dbd"
include "stringinRecord.dbd"
include "stringoutRecord.dbd"
include "subRecord.dbd"
include "subArrayRecord.dbd"
include "waveformRecord.dbd"
device(ai,CONSTANT,devAiSoft,"Soft Channel")
device(ai,CONSTANT,devAiSoftRaw,"Raw Soft Channel")
device(ao,CONSTANT,devAoSoft,"Soft Channel")
device(ao,CONSTANT,devAoSoftRaw,"Raw Soft Channel")
device(bi,CONSTANT,devBiSoft,"Soft Channel")
device(bi,CONSTANT,devBiSoftRaw,"Raw Soft Channel")
device(bo,CONSTANT,devBoSoft,"Soft Channel")
device(bo,CONSTANT,devBoSoftRaw,"Raw Soft Channel")
device(event,CONSTANT,devEventSoft,"Soft Channel")
device(longin,CONSTANT,devLiSoft,"Soft Channel")
device(longout,CONSTANT,devLoSoft,"Soft Channel")
device(mbbi,CONSTANT,devMbbiSoft,"Soft Channel")
device(mbbi,CONSTANT,devMbbiSoftRaw,"Raw Soft Channel")
device(mbbiDirect,CONSTANT,devMbbiDirectSoft,"Soft Channel")
device(mbbiDirect,CONSTANT,devMbbiDirectSoftRaw,"Raw Soft Channel")
device(mbbo,CONSTANT,devMbboSoft,"Soft Channel")
device(mbbo,CONSTANT,devMbboSoftRaw,"Raw Soft Channel")
device(mbboDirect,CONSTANT,devMbboDirectSoft,"Soft Channel")
device(mbboDirect,CONSTANT,devMbboDirectSoftRaw,"Raw Soft Channel")
device(stringin,CONSTANT,devSiSoft,"Soft Channel")
device(stringout,CONSTANT,devSoSoft,"Soft Channel")
device(subArray,CONSTANT,devSASoft,"Soft Channel")
device(waveform,CONSTANT,devWfSoft,"Soft Channel")