From 9a798bc05adf688748531dca7e659b9663654d0f Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Thu, 6 Feb 2014 16:46:47 -0500 Subject: [PATCH] more work on examples; documentation is only changed up to exampleServer --- .hgignore | 2 +- .../{RELEASE.local => ExampleRELEASE.local} | 0 configure/ExampleRELEASE.local | 7 + documentation/pvDatabaseCPP.html | 1034 ++++++++++------- exampleDatabase/Makefile | 16 + exampleDatabase/configure/CONFIG | 29 + exampleDatabase/configure/CONFIG_SITE | 39 + .../configure/ExampleRELEASE.local | 0 exampleDatabase/configure/Makefile | 8 + exampleDatabase/configure/RELEASE | 44 + exampleDatabase/configure/RULES | 6 + exampleDatabase/configure/RULES.ioc | 2 + exampleDatabase/configure/RULES_DIRS | 2 + exampleDatabase/configure/RULES_TOP | 3 + exampleDatabase/example/Db/Makefile | 28 + exampleDatabase/example/Db/dbArray.db | 9 + exampleDatabase/example/Db/dbCounter.db | 20 + exampleDatabase/example/Db/dbEnum.db | 14 + exampleDatabase/example/Db/dbInteger.db | 16 + exampleDatabase/example/Db/dbScalar.db | 17 + exampleDatabase/example/Db/dbString.db | 3 + exampleDatabase/example/Db/dbStringArray.db | 5 + exampleDatabase/example/Makefile | 8 + exampleDatabase/example/src/Makefile | 40 + .../example/src/exampleDatabaseInclude.dbd | 3 + .../example/src/exampleDatabaseMain.cpp | 57 + exampleDatabase/iocBoot/Makefile | 7 + .../iocBoot/exampleDatabase/Makefile | 5 + .../iocBoot/exampleDatabase/st.cmd | 21 + exampleDatabase/src/Makefile | 38 + exampleDatabase/src/exampleDatabase.cpp | 138 +++ exampleDatabase/src/exampleDatabase.h | 27 + .../src/exampleDatabaseInclude.dbd | 1 + exampleDatabase/src/exampleDatabaseMain.cpp | 60 + .../src/exampleDatabaseRegister.cpp | 60 + exampleLink/configure/ExampleRELEASE.local | 8 + examplePowerSupply/Makefile | 16 + examplePowerSupply/configure/CONFIG | 29 + examplePowerSupply/configure/CONFIG_SITE | 39 + .../configure/ExampleRELEASE.local | 8 + examplePowerSupply/configure/Makefile | 8 + examplePowerSupply/configure/RELEASE | 44 + examplePowerSupply/configure/RULES | 6 + examplePowerSupply/configure/RULES.ioc | 2 + examplePowerSupply/configure/RULES_DIRS | 2 + examplePowerSupply/configure/RULES_TOP | 3 + examplePowerSupply/example/Db/Makefile | 28 + examplePowerSupply/example/Db/dbArray.db | 9 + examplePowerSupply/example/Db/dbCounter.db | 20 + examplePowerSupply/example/Db/dbEnum.db | 14 + examplePowerSupply/example/Db/dbInteger.db | 16 + examplePowerSupply/example/Db/dbScalar.db | 17 + examplePowerSupply/example/Db/dbString.db | 3 + .../example/Db/dbStringArray.db | 5 + examplePowerSupply/example/Makefile | 8 + examplePowerSupply/example/src/Makefile | 40 + .../example/src/powerSupplyInclude.dbd | 5 + .../example/src/powerSupplyMain.cpp | 31 + examplePowerSupply/iocBoot/Makefile | 7 + .../iocBoot/powerSupply/Makefile | 5 + examplePowerSupply/iocBoot/powerSupply/st.cmd | 23 + examplePowerSupply/src/Makefile | 38 + examplePowerSupply/src/powerSupply.cpp | 179 +++ examplePowerSupply/src/powerSupply.h | 58 + examplePowerSupply/src/powerSupplyInclude.dbd | 1 + examplePowerSupply/src/powerSupplyMain.cpp | 68 ++ .../src/powerSupplyRegister.cpp | 69 ++ exampleServer/configure/ExampleRELEASE.local | 8 + exampleServer/example/src/Makefile | 2 +- exampleServer/iocBoot/exampleServer/st.cmd | 2 +- exampleServer/src/Makefile | 23 +- exampleServer/src/exampleServerMain.cpp | 67 ++ src/Makefile | 1 - src/special/recordList.cpp | 6 +- src/special/traceRecord.cpp | 6 +- test/src/Makefile | 3 + .../src/powerSupply.cpp | 114 +- test/src/powerSupply.h | 58 + test/src/testExampleRecord.cpp | 30 +- test/src/testPVCopy.cpp | 33 +- test/src/testPVRecord.cpp | 35 +- 81 files changed, 2361 insertions(+), 605 deletions(-) rename arrayPerformance/configure/{RELEASE.local => ExampleRELEASE.local} (100%) create mode 100644 configure/ExampleRELEASE.local create mode 100644 exampleDatabase/Makefile create mode 100644 exampleDatabase/configure/CONFIG create mode 100644 exampleDatabase/configure/CONFIG_SITE rename exampleLink/configure/RELEASE.local => exampleDatabase/configure/ExampleRELEASE.local (100%) create mode 100644 exampleDatabase/configure/Makefile create mode 100644 exampleDatabase/configure/RELEASE create mode 100644 exampleDatabase/configure/RULES create mode 100644 exampleDatabase/configure/RULES.ioc create mode 100644 exampleDatabase/configure/RULES_DIRS create mode 100644 exampleDatabase/configure/RULES_TOP create mode 100644 exampleDatabase/example/Db/Makefile create mode 100644 exampleDatabase/example/Db/dbArray.db create mode 100644 exampleDatabase/example/Db/dbCounter.db create mode 100644 exampleDatabase/example/Db/dbEnum.db create mode 100644 exampleDatabase/example/Db/dbInteger.db create mode 100644 exampleDatabase/example/Db/dbScalar.db create mode 100644 exampleDatabase/example/Db/dbString.db create mode 100644 exampleDatabase/example/Db/dbStringArray.db create mode 100644 exampleDatabase/example/Makefile create mode 100644 exampleDatabase/example/src/Makefile create mode 100644 exampleDatabase/example/src/exampleDatabaseInclude.dbd create mode 100644 exampleDatabase/example/src/exampleDatabaseMain.cpp create mode 100644 exampleDatabase/iocBoot/Makefile create mode 100644 exampleDatabase/iocBoot/exampleDatabase/Makefile create mode 100644 exampleDatabase/iocBoot/exampleDatabase/st.cmd create mode 100644 exampleDatabase/src/Makefile create mode 100644 exampleDatabase/src/exampleDatabase.cpp create mode 100644 exampleDatabase/src/exampleDatabase.h create mode 100644 exampleDatabase/src/exampleDatabaseInclude.dbd create mode 100644 exampleDatabase/src/exampleDatabaseMain.cpp create mode 100644 exampleDatabase/src/exampleDatabaseRegister.cpp create mode 100644 exampleLink/configure/ExampleRELEASE.local create mode 100644 examplePowerSupply/Makefile create mode 100644 examplePowerSupply/configure/CONFIG create mode 100644 examplePowerSupply/configure/CONFIG_SITE create mode 100644 examplePowerSupply/configure/ExampleRELEASE.local create mode 100644 examplePowerSupply/configure/Makefile create mode 100644 examplePowerSupply/configure/RELEASE create mode 100644 examplePowerSupply/configure/RULES create mode 100644 examplePowerSupply/configure/RULES.ioc create mode 100644 examplePowerSupply/configure/RULES_DIRS create mode 100644 examplePowerSupply/configure/RULES_TOP create mode 100644 examplePowerSupply/example/Db/Makefile create mode 100644 examplePowerSupply/example/Db/dbArray.db create mode 100644 examplePowerSupply/example/Db/dbCounter.db create mode 100644 examplePowerSupply/example/Db/dbEnum.db create mode 100644 examplePowerSupply/example/Db/dbInteger.db create mode 100644 examplePowerSupply/example/Db/dbScalar.db create mode 100644 examplePowerSupply/example/Db/dbString.db create mode 100644 examplePowerSupply/example/Db/dbStringArray.db create mode 100644 examplePowerSupply/example/Makefile create mode 100644 examplePowerSupply/example/src/Makefile create mode 100644 examplePowerSupply/example/src/powerSupplyInclude.dbd create mode 100644 examplePowerSupply/example/src/powerSupplyMain.cpp create mode 100644 examplePowerSupply/iocBoot/Makefile create mode 100644 examplePowerSupply/iocBoot/powerSupply/Makefile create mode 100644 examplePowerSupply/iocBoot/powerSupply/st.cmd create mode 100644 examplePowerSupply/src/Makefile create mode 100644 examplePowerSupply/src/powerSupply.cpp create mode 100644 examplePowerSupply/src/powerSupply.h create mode 100644 examplePowerSupply/src/powerSupplyInclude.dbd create mode 100644 examplePowerSupply/src/powerSupplyMain.cpp create mode 100644 examplePowerSupply/src/powerSupplyRegister.cpp create mode 100644 exampleServer/configure/ExampleRELEASE.local create mode 100644 exampleServer/src/exampleServerMain.cpp rename src/special/powerSupplyRecordTest.h => test/src/powerSupply.cpp (55%) create mode 100644 test/src/powerSupply.h diff --git a/.hgignore b/.hgignore index 20e12e6..9b9ff22 100644 --- a/.hgignore +++ b/.hgignore @@ -7,5 +7,5 @@ db/ dbd/ documentation/html envPaths -configure/.*\.local +RELEASE.local /O\..* diff --git a/arrayPerformance/configure/RELEASE.local b/arrayPerformance/configure/ExampleRELEASE.local similarity index 100% rename from arrayPerformance/configure/RELEASE.local rename to arrayPerformance/configure/ExampleRELEASE.local diff --git a/configure/ExampleRELEASE.local b/configure/ExampleRELEASE.local new file mode 100644 index 0000000..dc46b3e --- /dev/null +++ b/configure/ExampleRELEASE.local @@ -0,0 +1,7 @@ + +TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top + +EPICS_BASE=/home/install/epics/base +PVCOMMON=/home/hg/pvCommonCPP +PVDATA=/home/hg/pvDataCPP +PVACCESS=/home/hg/pvAccessCPP diff --git a/documentation/pvDatabaseCPP.html b/documentation/pvDatabaseCPP.html index 87b1425..ce3328f 100644 --- a/documentation/pvDatabaseCPP.html +++ b/documentation/pvDatabaseCPP.html @@ -38,7 +38,7 @@

pvDatabaseCPP

-

EPICS v4 Working Group, Working Draft, 21-Nov-2013

+

EPICS v4 Working Group, Working Draft, 06-Feb-2014

Latest version:

Status of this Document

-

This is the 21-Nov-2013 version of of pvDatabaseCPP.

+

This is the 06-Feb-2014 version of of pvDatabaseCPP.

-

All channel methods except channelRPC, which is implemented -by pvAccess, have been implemented. +

+Since the last version of the documentation: +

+
examples
+
The examples have been moved to separate top level build areas.
+
test
+
The regression tests have been moved to a separate top level build area. + It is built from the top but nothing from the tests appears in the top + level bin directory. +
exampleServer
+
This example now also includes pvaSrv, i. e. the pvAccess server for + interfacing to iocCore V3 records. +
+
+

This project is ready for alpha users.

-

Since the last version the longArrayGet and longArrayPut examples were added. -More testing for monitor queues and memory leaks was done. -Everything looks good!! -But there are still two unresolved problems: +

+I have not had time to look at +two unresolved problems reported in the previous version of this document:

memory leak
arrayPerformanceMain shows a slight memory leak at termination.
@@ -104,11 +116,6 @@ But there are still two unresolved problems:

Future enhancements in priority order:

-
Separate example that also has pvaSrv
-
Create a separate example that combines a V3IOC, - a pvDatabase, and pvaSrv. - This will not be done until pvDataCPP-md is merged into pvDataCPP. -
channelArray
The arguments that have type int should be changed to size_t This will not be done until pvDataCPP-md is merged into pvDataCPP. @@ -116,8 +123,9 @@ But there are still two unresolved problems:
Monitor Algorithms
Monitor algorithms have not been implemented. Thus all monitors are onPut.
-
Create regression tests
-
Currently only examples exist and have been used for testing.
+
Create more regression tests
+
Currently only some simple tests exist. + Most of the testing has been via the examples.
@@ -128,6 +136,13 @@ But there are still two unresolved problems:

Introduction

Overview

+

The main purpose of this project to make it easier to implement services that are accessed via pvAccess. +What this project supplies is a complete implementation of the server side of pvAccess. +All that a service has to provide is a top level PVStructure and a process method. +A service can be run as a main process or can be part of a V3 IOC. +Thus services can be developed that interact with V3 records, asynDriver, +areaDetector, etc. +

A brief description of a pvDatabase is that it is a set of network accessible, smart, memory resident records. Each record has data composed of a top level PVStructure. @@ -158,23 +173,10 @@ A record is smart because code can be attached to a record, which is accessed vi This component also includes the monitor and pvCopy components from pvIOCJava

Main and V3IOC
The pvDatabase can be provided via a Main program or can be part - of a V3IOC. In tha later case the IOC has both a database of V3 Records + of a V3IOC. In the later case the IOC has both a database of V3 Records and a pvDatabase.
-
exampleCounter
-
This is a simple example showing how to create a PVRecord and - how to deploy it either as a standalone process or as part of a V3IOC.
-
exampleServer
-
This example has a set of PVRecords. - Again the records can be deployed either as a standalone process or - as part of a V3IOC.
-
examplePVADoubleArrayGet
-
This is an example PVRecord that uses channelGet to get an array of doubles from - another PVRecord via pvAccess. The example shows how to get the value either via - remote pvAccess or by directly accessing the local channelProvider. - Again the records can be deployed either as a standalone process or - as part of a V3IOC.
-

database provides base classes that make it easy to create record instances. +

Base classes make it easy to create record instances. The code attached to each record must create the top level PVStructure and the following three methods:

@@ -189,96 +191,100 @@ level PVStructure and the following three methods:

This releases and resources used by the implementation.

Getting started

-

Included with this project are three examples that are useful for -seeing how pvDatabase can be used by clients. -Each can be deployed either as a standalone process or as part of a V3IOC. -The examples are: -

-
exampleCounterMain
-
This has a database consisting of a single record named exampleCounter: - The exampleCounter is discussed in a following section.
-
exampleCounter
-
This is exampleCounter as part of a V3IOC.
-
exampleServerMain
-
This has a database with several records.
-
exampleServer
-
This is exampleServer as part of a V3IOC
-
examplePVADoubleArrayGetMain
-
This is the example of how to use pvAccess to get data.
-
examplePVADoubleArrayGet
-
This is examplePVADoubleArrayGet as part of a V3IOC
- -

-

exampleCounter

-

To start exampleCounterMain: +

The first step is to build pvDatabaseCPP as described in the next section.

+

One of the examples is exampleServer. +It can be started either via a main program or as part of a V3 IOC. +

+

To start it as a main program do the following:

 mrk> pwd
-/home/hg/pvDatabaseCPP
-mrk> bin/linux-x86_64/exampleCounterMain
-

-

To start exampleCounter as part of a V3IOC: +/home/hg/pvDatabaseCPP/exampleServer +mrk> bin/linux-x86_64/exampleServerMain + +

You should see something like the following:

+
+result of addRecord exampleServer 1
+VERSION : pvAccess Server v3.0.5-SNAPSHOT
+PROVIDER_NAMES : local
+BEACON_ADDR_LIST : 
+AUTO_BEACON_ADDR_LIST : 1
+BEACON_PERIOD : 15
+BROADCAST_PORT : 5076
+SERVER_PORT : 5075
+RCV_BUFFER_SIZE : 16384
+IGNORE_ADDR_LIST: 
+STATE : INITIALIZED
+exampleServer
+Type exit to stop: 
+
+

Then in another window execute a pvput and pvget as follows:

+
+mrk> pvput -r "field(argument.value)" exampleServer World
+...
+mrk> pvget -r "record{process=true}field(result.value)" exampleServer
+exampleServer
+structure 
+    string value Hello World
+mrk> 
+
+

To run the example as part of a V3 IOC do the following:

 mrk> pwd
-/home/hg/pvDatabaseCPP/iocBoot/exampleCounter
-mrk> ../../../bin/linux-x86_64/exampleCounter st.cmd
-

-

You can then issue the commands dbl and pvdbl: -

-epics> dbl
-double01
-epics> pvdbl
-exampleCounter
+/home/hg/pvDatabaseCPP/exampleServer/iocBoot/exampleServer
+mrk> ../../bin/linux-x86_64/exampleServer st.cmd 
+> envPaths
+epicsEnvSet("ARCH","linux-x86_64")
+epicsEnvSet("IOC","exampleServer")
+epicsEnvSet("TOP","/home/hg/pvDatabaseCPP/exampleServer")
+epicsEnvSet("EPICS_BASE","/home/install/epics/base")
+epicsEnvSet("EPICSV4HOME","/home/hg")
+cd /home/hg/pvDatabaseCPP/exampleServer
+## Register all support components
+dbLoadDatabase("dbd/exampleServer.dbd")
+exampleServer_registerRecordDeviceDriver(pdbbase)
+## Load record instances
+dbLoadRecords("db/dbScalar.db","name=pvdouble,type=ao")
+dbLoadRecords("db/dbArray.db","name=pvdoubleArray,type=DOUBLE")
+dbLoadRecords("db/dbStringArray.db","name=pvstringArray")
+dbLoadRecords("db/dbEnum.db","name=pvenum")
+dbLoadRecords("db/dbCounter.db","name=pvcounter");
+cd /home/hg/pvDatabaseCPP/exampleServer/iocBoot/exampleServer
+iocInit()
+Starting iocInit
+############################################################################
+## EPICS R3.14.12.3 $Date: Mon 2012-12-17 14:11:47 -0600$
+## EPICS Base built Dec 21 2013
+############################################################################
+iocRun: All initialization complete
+dbl
+pvdouble
+pvcounter
+pvenum
+pvdoubleArray
+pvstringArray
+epicsThreadSleep(1.0)
+exampleServerCreateRecord pvaServer
+startPVAServer
+VERSION : pvAccess Server v3.0.5-SNAPSHOT
+PROVIDER_NAMES : dbPv local
+BEACON_ADDR_LIST : 
+AUTO_BEACON_ADDR_LIST : 1
+BEACON_PERIOD : 15
+BROADCAST_PORT : 5076
+SERVER_PORT : 5075
+RCV_BUFFER_SIZE : 16384
+IGNORE_ADDR_LIST: 
+STATE : INITIALIZED
+pvdbl
+pvaServer
 epics> 
 
-double01 is a v3Record. -exampleCounter is a pvRecord. -

-

Starting exampleServer is similar. -After successfully running exampleCounterMain and exampleCounter then -try starting exampleServerMain and exampleServer. -

-

exampleServer

-

This example provides the exampleCounter record in addition to a number of other PVRecords. -Like exampleCounter it can be started either as a standalone main program or as -a part of a V3IOC. -The exampleServer pvDatabase has many records including the following:

-
-
exampleCounter
-
A record that is an instance of exampleCounter described below. - The most useful channel methods are channelGet, channelProcess, - and monitor.
-
exampleDouble
-
A record that is an instance of a record with a process method - that does nothing. To test it start a channelPut and a channelGet and/or monitor.
-
exampleDoubleArray
-
An array record that is an instance of a record with a process method - that does nothing. It can be tested like exampleDouble. In addition channelArray can - also be used.
-
examplePowerSupply
-
Can be used by channelGet, channelPut, channelPutGet, and monitor.
-
laptoprecordListPGRPC
-
Implements the record expected by swtshell channelList. - It can also be used via channelPutGet.
-
traceRecordPGRPC
-
This can be used via channelPutGet to set the trace level of another record.
-
-

It also has a number of other scalar and array records.

-

swtshell

-

The Java program - - swtshell -can be used to access pvDatabase.

-

In particular read the sections "Getting Started" and "Simple Example". -They will work on the exampleServer with the following differences: -

-
startExample.zip
-
Do NOT use this. Instead run the exampleServer as described above.
-
channelList result
-
The result of channelList will show the list of records that - exampleServer has rather than the records from startExample.zip
-
+

Just like previously you can then execute a pvput and pvget and see Hello World.

+

The examples, i. e. exampleServer, exampleLink, examplePowerSupple, +and exampleDatabase, are described in separate sections below. +In addition arrayPerformance can be used to measure that performance of big +arrays. It is also described in a later section.

Relationship with pvIOCJava.

This document descibes a C++ implementation of some of the components in pvIOCJava, @@ -301,239 +307,6 @@ channelRPC. For channelRPC pvAccess provides (or will provide) a thread pool for If, in the future, a scanning facility is provided by pvDatabaseCPP or some other facility, then the scanning facility will have to provide some way of handling process requests that block.

-

Example PVRecord Extension

-

The example implements a simple counter. -The example can be run on linux as follows:

-
-mrk> pwd
-/home/hg/pvDatabaseCPP
-mrk> bin/linux-x86_64/exampleCounter 
-
-
-

The example consists of four components:

-
-
ExampleCounter.h
-
The source code for the counter. - It is located in directory pvDatabaseCPP/example/src/exampleCounter. -
-
exampleCounterMain.cpp
-
A main program that runs the example so that it can be accessed - by a pvAccess client. - It is located in directory pvDatabaseCPP/example/exampleCounter. -
-
V3IOC/exampleCounter
-
This is a directory that packages exampleCounter to make it - part of a V3IOC.
-
iocBoot/exampleCounter
-
A place to start exampleCounter as part of a V3IOC. - It follows the normal iocCore conventions.
-
-

ExampleCounter.h

-

The example resides in src/database. -The complete implementation is in the header file. -A serious implementation might break the code into a header and an -implementation file.

-

The description consists of

-
-class ExampleCounter;
-typedef std::tr1::shared_ptr<ExampleCounter> ExampleCounterPtr;
-
-class ExampleCounter :
-    public PVRecord
-{
-public:
-    POINTER_DEFINITIONS(ExampleCounter);
-    static ExampleCounterPtr create(
-        epics::pvData::String const & recordName);
-    virtual ~ExampleCounter();
-    virtual void destroy();
-    virtual bool init();
-    virtual void process();
-private:
-    ExampleCounter(epics::pvData::String const & recordName,
-        epics::pvData::PVStructurePtr const & pvStructure);
-    epics::pvData::PVLongPtr pvValue;
-    epics::pvData::PVTimeStamp pvTimeStamp;
-    epics::pvData::TimeStamp timeStamp;
-};
-
-

where

-
-
create
-
This is example specific but each support could provide - a similar static method. -
-
~ExampleCounter
-
The destructor must be declared virtual.
-
destroy
-
Called when the record is being destroyed. - This must call the base class destroy method. -
init
-
A method to initialize the support. It returns true - if initialization is successful and false if not. - NOTE that this is a virtual method of PVRecord itself.
-
process
-
- This again is a virtual method of PVRecord. -
-
ExampleCounter
-
For the example this is private.
-
pvValue
-
This is the field of the top level structure that process - accesses. -
-
-

The implementation of create method is:

-
-ExampleCounterPtr ExampleCounter::create(
-    epics::pvData::String const & recordName)
-{
-    epics::pvData::PVStructurePtr pvStructure =
-       epics::pvData::getStandardPVField()->scalar(
-           epics::pvData::pvDouble,"timeStamp,alarm"");
-    ExampleCounterPtr pvRecord(
-        new ExampleCounter(recordName,pvStructure));
-    if(!pvRecord->init()) pvRecord.reset();
-    return pvRecord;
-}
-
-This: -
    -
  • Creates the top level structure.
  • -
  • Creates a ExampleCounterPtr via the constructor.
  • -
  • Calls init and if it fails resets the shared pointer.
  • -
  • Returns the shared pointer to the newly created record.
  • -
-

The private constructor method is:

-
-ExampleCounter::ExampleCounter(
-    epics::pvData::String const & recordName,
-    epics::pvData::PVStructurePtr const & pvStructure)
-: PVRecord(recordName,pvStructure)
-{
-    pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
-}
-
-The example is very simple. Note that it calls the base class constructor. -

The destructor and destroy methods are:

-
-ExampleCounter::~ExampleCounter()
-{
-}
-
-void ExampleCounter::destroy()
-{
-    PVRecord::destroy();
-}
-
-The destructor has nothing to do. -The destroy method, which is virtual, just calls the destroy method of the base class. -A more complicated example can clean up any resources it used but must call the base -class destroy method. -

The implementation of init is:

-
-bool ExampleCounter::init()
-{
-
-    initPVRecord();
-    epics::pvData::PVFieldPtr pvField;
-    pvValue = getPVStructure()->getLongField("value");
-    if(pvValue==NULL) return false;
-    return true;
-}
-
-This: -
    -
  • Calls initRecord which is implemented by the base class. - It MUST be called.
  • -
  • Calls getLongField to get the interface to the value field, - which must be a scalar with type long.
  • -
  • If a long value field was not found it returns false.
  • -
  • Returns true
  • -
-

The implementation of process is:

-
-void ExampleCounter::process()
-{
-    pvValue->put(pvValue->get() + 1.0);
-    timeStamp.getCurrent();
-    pvTimeStamp.set(timeStamp);
-}
-
-It adds 1.0 to the current value. -It then sets the timeStamp to the current time. -

exampleCounterMain.cpp

-

NOTE: -This is a shorter version of the actual code. -It shows the essential code. -The actual example shows how create an additional record. -

-

The main program is:

-
-int main(int argc,char *argv[])
-{
-    PVDatabasePtr master = PVDatabase::getMaster();
-    ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create();
-    String recordName("exampleCounter");
-    PVRecordPtr pvRecord = ExampleCounter::create(recordName);
-    bool result = master->addRecord(pvRecord);
-    cout << "result of addRecord " << recordName << " " << result << endl;
-    pvRecord.reset();
-    startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
-    cout << "exampleCounter\n";
-    string str;
-    while(true) {
-        cout << "Type exit to stop: \n";
-        getline(cin,str);
-        if(str.compare("exit")==0) break;
-
-    }
-    return 0;
-}
-
-This: -
    -
  • Gets a pointer to the master database.
  • -
  • Creates the local Channel Provider. This starts the pvAccess server.
  • -
  • Creates a ExampleCounter record with the name exampleCounter -
  • -
  • Prints exampleCounter on standard out.
  • -
  • Runs forever until the user types exit on standard in.
  • -
-

V3IOC exampleCounter

-

This has two subdirectories: -

-
Db
-
This has a template for a single v3Record.
-
src
-
This has code to allow exampleCounter to reside in a V3IOC.
-
-

-

The src directory has the following components:

-
-
exampleCounterMain.cpp
-
This is just a standard Main for a V3IOC.
-
exampleCounterInclude.dbd
-
This is: -
-include "base.dbd"
-include "PVAServerRegister.dbd"
-registrar("exampleCounterRegister")
-       
- This includes the dbd components required from base, - the dbd file for starting pvAccess and the local channelProvider, - and the dbd file for the example. The later is for the code from the - next file. -
-
exampleCounter.cpp
-
This is the code that registers a command the can be issued - via the iocsh, which is the console for a V3IOC. - The example supports a single command: -
-exampleCounterCreateRecord recordName
-       
-
-

Phased Development

This documentation describes the first phase of a phased implementation of pvDatabaseCPP:

@@ -581,7 +354,7 @@ The rest of this document discusses only the first phase.

Minumum Features Required for pvRecord

The first phase will only implement record processing, i. e. the process method has to do everything itself without any generic field support. -This will be sufficient for starting to implement services. +This will be sufficient for implementing many services. The following are the minimium features required

PVDatabase
@@ -601,6 +374,72 @@ The following are the minimium features required

The following sections describes the classes required for the first phase.

+

swtshell

+

The Java program + + swtshell +can be used to access pvDatabase.

+

In particular read the sections "Getting Started" and "exampleServer". +They will work on the exampleServer with the following differences: +

+
startExample.zip
+
Do NOT use this. Instead run the exampleServer as described above.
+
channelList result
+
The result of channelList will show the list of records that + exampleServer has rather than the records from startExample.zip
+
+

The exampleService shown below provides an example of using swtshell.

+ +

Building pvDatabaseCPP

+

To build pvDatabaseCPP You must provide a file RELEASE.local +in directory configure. +Thus do the following:

+
+mrk> pwd
+/home/hg/pvDatabaseCPP/configure
+mrk> cp ExampleRELEASE.local RELEASE.local
+
+

Then edit RELEASE.local so that it has the correct location of each +product pvDatabaseCPP requires. +Than at the top level just execute make:

+
+mrk> cd ..
+mrk> pwd
+/home/hg/pvDatabaseCPP
+mrk> make
+
+

This builds pvDatabaseCPP and also the tests.

+

Each example and arrayPerformance is build as a completely separate top. +This is done so that:

+

    +
  1. + It is easier to understand each example including how it is built so that + it can be run as a main or as part of a V3 IOC. +
  2. +
  3. + Each example can be copied somewhere else and used as the basis + for creating a new service. +
  4. +
+

Thus to build each example just follow the same instructions as for +building pvDatabaseCPP itself. +For example:

+
+mrk> pwd
+/home/hg/pvDatabaseCPP/exampleServer/configure
+mrk> cp ExampleRELEASE.local RELEASE.local
+
+

Then edit RELEASE.local so that it has the correct location of each +product the example requires. +Than at the top level just execute make:

+
+mrk> cd ..
+mrk> pwd
+/home/hg/pvDatabaseCPP/exampleServer
+mrk> make
+
+

This builds the example.

iocshell commands

The following iocsh commands are provided for a V3IOC:

@@ -652,20 +491,11 @@ See example/V3IOC/exampleCounter/src/ for a simple example.

src/special

This directory has the following files:

-
powerSupplyRecordTest.h
-
- This provides code that simulates a power supply. - It computes the current from the voltage and power. - It is used for testing. - The complete implementation is provided in the header file. - Thus code will be generated only if other code includes the - header file and creates a record instance. -
recordList.h
This implements a PVRecord that provides a list of the names of the records in the PVDatabase. It also serves as an example of how to implement a service. - The testExampleServer creates an instance via the following code: + The exampleDatabase creates an instance via the following code:
 recordName = "laptoprecordListPGRPC";
 pvRecord = RecordListRecord::create(recordName);
@@ -1283,93 +1113,322 @@ pvRecord = RecordListRecord::create(recordName);
 result = master->addRecord(pvRecord);
 if(!result) cout<< "record " << recordName << " not added" << endl;
 
-

powerSupplyRecordTest

-

This simulates a simple power supply record. -It is used for testing.

-

Accessing Other PVRecords

-

This section 1) starts with a discussion of accessing data via pvAccess -and 2) gives a brief description of an example that gets data for an array of doubles.

-

Discussion

-

Access Alternatives

-

The process routine of a PVRecord can access other PVRecords in two ways:

-
-
Directly accessing local pvDatabase
-
- If the other PVRecord is accessed via the master PVDatabase then - threading issues are up to the implementation. - For now this method will not be discussed.
-
Access via pvAccess
-
- If access is via pvAccess then locking is handled by pvAccess.
-
-

Access via pvAccess can be done either by local or remote channel provider.

-
-
-
Access via channelProviderLocal
-
- If the local pvAccess server is used the implementation must be careful that it does not - caused deadlocks. - When the process method is called the pvRecord for the process method is locked. - When it makes a pvAccess get, put, etc request the other record is locked. - Thus if a set of pvAccess links are implemented the possibility of deadlocks - exists. A simple example is two records that have links to each other. - More complex sets are easily created. - Unless the developer has complete control of the set of records then remote pvAccess should - be used. - But this results in more context switches. -
-
Access via remote pvAccess
-
If remote pvAccess is used then all lockimg issues are handled by pvAccess. - The linked channel can be a pvRecord in the local pvDatabase or can be implemented - by a remote pvAccess server.
-
-

Data synchronization

-

If pvAccess is used then it handles data synchronization. -This is done by making a copy of the data that is transfered between the two pvRecords. -This is true if either remote or local pvAccess is used. -Each get, put, etc request results in data being copied between the two records.

-

-If the linked channel is a local pvRecord then, -for scalar and structure arrays, -raw data is NOT copied for gets. -This is because pvData uses shared_vector to hold the raw data. -Instead of copying the raw data the reference count is incremented.

-

For puts the linked array will force a new allocation of the raw data in the linked record, -i. e. copy on write semantics are enforced. This is done automatically -by pvData and not by pvDatabase.

-

Some details

-

As mentioned before a pvDatabase server can be either a separate process, -i. e. a main program, or can be part of a V3IOC.

-

A main pvDatabase server issues the following calls:

-
- ClientFactory::start();
- ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
- ...
- ServerContext::shared_pointer serverContext = startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
-
-

The first call is only necessary if some of the pvRecords -have pvAccess links. -These must be called before any code that uses links is initialized. -After these two calls there will be two channel providers: local, and pvAccess. +

-

-

A pvDatabase that is part of a V3IOC has the following in the st.cmd file.

+

exampleServer

+

The example implements a simple service that has a top level pvStructure:

-...
-iocInit()
-startPVAClient
-startPVAServer
-## commands to create pvRecords
+structure
+    structure argument
+        string value
+    structure result
+        string value
+        time_t timeStamp
+            long secondsPastEpoch
+            int nanoSeconds
+            int userTag
+
+

It is designed to be accessed via a channelPutGet request. +The client sets argument.value +When the record processes it sets result.value to "Hello " +concatenated with argument.value. +Thus if the client sets argument.value equal to "World" +result.value will be "Hello World". +In addition the timeStamp is set to the time when process is called.

+

+The example can be run on linux as follows:

+
+mrk> pwd
+/home/hg/pvDatabaseCPP/exampleService
+mrk> bin/linux-x86_64/exampleService
 

-Once the client and local provider code has started then the following creates a channel access link. -

-
-PVDatabasePtr master = PVDatabase::getMaster();
-ChannelAccess::shared_pointer channelAccess = getChannelAccess();
-ChannelProvider::shared_pointer provider = channelAccess->getProvider(providerName);
-Channel::shared_pointer channel = provider->createChannel(channelName,channelRequester);
+The directory structure is:
 
+exampleServer + configure + ExampleRELEASE.local + ... + src + exampleServer.h + exampleServer.cpp + exampleServerInclude.dbd + exampleServerMain.cpp + exampleServerRegister.cpp + example + Db + dbArray.db + ... + src + exampleServerInclude.dbd + exampleServerMain.cpp + iocBoot + exampleServer + st.cmd + ... + +where +
+
ExampleRELEASE.local
+
This is the file that must be copied to RELEASE.local + and edited.
+
exampleServer.h
+
The header file for the service.
+
exampleServer.cpp
+
The service implementation.
+
exampleServerMain.cpp
+
A main program that runs the example so that it can be accessed + by a pvAccess client. +
+
exampleServerInclude.dbd
+
This has a register command so that the service can be started + on a V3 IOC via iocsh. +
+
exampleServerRegister.cpp
+
This has the code to start the service via the following iocsh + command. +
+exampleServerCreateRecord exampleServer
+
+ Multiple commands can be issued to create multiple service records. +
+
example
+
This is for building a V3 IOC application.
+
example/Db
+
This has template files for creating V3 records.
+
example/src/exampleServerInclude.dbd
+
The commands to build a V3 database
+
example/src/exampleServerMain.cpp
+
The source file for running a V3 IOC.
+
iocBoot/exampleServer
+
A place to start exampleServer as part of a V3IOC. + It has a st.cmd file that starts the ioc and also starts pvAccess + and the example.
+
+

exampleServer.h

+

The example resides in src +The implementation is in exampleServer.cpp. +A serious implementation might break the code into a header and an +implementation file.

+

The description consists of

+
+class ExampleServer;
+typedef std::tr1::shared_ptr<ExampleServer> ExampleServerPtr;
+
+class ExampleServer :
+    public PVRecord
+{
+public:
+    POINTER_DEFINITIONS(ExampleServer);
+    static ExampleServerPtr create(
+        epics::pvData::String const & recordName);
+    virtual ~ExampleServer();
+    virtual void destroy();
+    virtual bool init();
+    virtual void process();
+private:
+    ExampleServer(epics::pvData::String const & recordName,
+        epics::pvData::PVStructurePtr const & pvStructure);
+
+    epics::pvData::PVStringPtr pvArgumentValue;
+    epics::pvData::PVStringPtr pvResultValue;
+    epics::pvData::PVTimeStamp pvTimeStamp;
+    epics::pvData::TimeStamp timeStamp;
+};
+
+

where

+
+
create
+
This is example specific but each support could provide + a similar static method. +
+
~ExampleServer
+
The destructor must be declared virtual.
+
destroy
+
Called when the record is being destroyed. + This must call the base class destroy method. +
init
+
A method to initialize the support. It returns true + if initialization is successful and false if not. + NOTE that this is a virtual method of PVRecord itself.
+
process
+
+ This again is a virtual method of PVRecord. +
+
ExampleServer
+
For the example this is private.
+
pvValue
+
This is the field of the top level structure that process + accesses. +
+
+

The implementation of create method is:

+
+ExampleServerPtr ExampleServer::create(
+    epics::pvData::String const & recordName)
+{
+    StandardPVFieldPtr standardPVField = getStandardPVField();
+    PVDataCreatePtr pvDataCreate = getPVDataCreate();
+    PVStructurePtr pvArgument = standardPVField->scalar(pvString,"");
+    PVStructurePtr pvResult = standardPVField->scalar(pvString,"timeStamp");
+    StringArray names;
+    names.reserve(2);
+    PVFieldPtrArray fields;
+    fields.reserve(2);
+    names.push_back("argument");
+    fields.push_back(pvArgument);
+    names.push_back("result");
+    fields.push_back(pvResult);
+    PVStructurePtr pvStructure = pvDataCreate->createPVStructure(names,fields);
+    ExampleServerPtr pvRecord(
+        new ExampleServer(recordName,pvStructure));
+    if(!pvRecord->init()) pvRecord.reset();
+    return pvRecord;
+}
+
+This: +
    +
  • Creates the top level structure.
  • +
  • Creates a ExampleServerPtr via the constructor.
  • +
  • Calls init and if it fails resets the shared pointer.
  • +
  • Returns the shared pointer to the newly created record.
  • +
+

The private constructor method is:

+
+ExampleServer::ExampleServer(
+    epics::pvData::String const & recordName,
+    epics::pvData::PVStructurePtr const & pvStructure)
+: PVRecord(recordName,pvStructure)
+{
+}
+
+The example is very simple. Note that it calls the base class constructor. +

The destructor and destroy methods are:

+
+ExampleServer::~ExampleServer()
+{
+}
+
+void ExampleServer::destroy()
+{
+    PVRecord::destroy();
+}
+
+The destructor has nothing to do. +The destroy method, which is virtual, just calls the destroy method of the base class. +A more complicated example can clean up any resources it used but must call the base +class destroy method. +

The implementation of init is:

+
+bool ExampleServer::init()
+{
+    initPVRecord();
+    PVFieldPtr pvField;
+    pvArgumentValue = getPVStructure()->getStringField("argument.value");
+    if(pvArgumentValue.get()==NULL) return false;
+    pvResultValue = getPVStructure()->getStringField("result.value");
+    if(pvResultValue.get()==NULL) return false;
+    pvTimeStamp.attach(getPVStructure()->getSubField("result.timeStamp"));
+    return true;
+}
+
+

The implementation of process is:

+
+void ExampleServer::process()
+{
+    pvResultValue->put(String("Hello ") + pvArgumentValue->get());
+    timeStamp.getCurrent();
+    pvTimeStamp.set(timeStamp);
+}
+
+It gives a value to result.value and +then sets the timeStamp to the current time. +

exampleServerMain.cpp

+

NOTE: +This is a shorter version of the actual code. +It shows the essential code. +The actual example shows how create an additional record. +

+

The main program is:

+
+int main(int argc,char *argv[])
+{
+    PVDatabasePtr master = PVDatabase::getMaster();
+    ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create();
+    String recordName("exampleServer");
+    PVRecordPtr pvRecord = ExampleServer::create(recordName);
+    bool result = master->addRecord(pvRecord);
+    cout << "result of addRecord " << recordName << " " << result << endl;
+    pvRecord.reset();
+    startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
+    cout << "exampleServer\n";
+    string str;
+    while(true) {
+        cout << "Type exit to stop: \n";
+        getline(cin,str);
+        if(str.compare("exit")==0) break;
+
+    }
+    return 0;
+}
+
+This: +
    +
  • Gets a pointer to the master database.
  • +
  • Creates the local Channel Provider. This starts the pvAccess server.
  • +
  • Creates a ExampleServer record with the name exampleServer +
  • +
  • Prints exampleServer on standard out.
  • +
  • Runs forever until the user types exit on standard in.
  • +
+

V3IOC exampleServer

+

To start exampleServer as part of a V3IOC: +

+mrk> pwd
+/home/hg/pvDatabaseCPP/exampleServer/iocBoot/exampleServer
+mrk> ../../../bin/linux-x86_64/exampleServer st.cmd
+

+

You can then issue the commands dbl and pvdbl: +

+epics> dbl
+double01
+epics> pvdbl
+exampleServer
+epics> 
+
+double01 is a v3Record. +exampleServer is a pvRecord. +

+ +

exampleDatabase

+

exampleDatabase

+

This example provides the exampleCounter record in addition to a number of other PVRecords. +Like exampleCounter it can be started either as a standalone main program or as +a part of a V3IOC. +The exampleServer pvDatabase has many records including the following:

+
+
exampleCounter
+
A record that is an instance of exampleCounter described below. + The most useful channel methods are channelGet, channelProcess, + and monitor.
+
exampleDouble
+
A record that is an instance of a record with a process method + that does nothing. To test it start a channelPut and a channelGet and/or monitor.
+
exampleDoubleArray
+
An array record that is an instance of a record with a process method + that does nothing. It can be tested like exampleDouble. In addition channelArray can + also be used.
+
laptoprecordListPGRPC
+
Implements the record expected by swtshell channelList. + It can also be used via channelPutGet.
+
traceRecordPGRPC
+
This can be used via channelPutGet to set the trace level of another record.
+
+

It also has a number of other scalar and array records.

+

exampleLink

+

This example show how a service can access other PVRecords. +This section 1) starts with a discussion of accessing data via pvAccess +and 2) gives a brief description of an example that gets data for an array of doubles.

examplePVADoubleArrayGet

examplePVADoubleArrayGet shows how to use pvAccess to get data.

The code resides in three directories:

@@ -1383,7 +1442,7 @@ examplePVADoubleArrayGet shows how to use pvAccess to get data.

iocBoot/examplePVADoubleArrayGet
This has the st.cmd files to start the example.
-

examplePVADoubleArrayGet Implementation

+

examplePVADoubleArrayGet Implementation

examplePVADoubleArrayGet.h contains the following:

 ...
@@ -1593,7 +1652,102 @@ where
    
st.remote
This creates the example using the remote channel provider.
+

Discussion

+

Access Alternatives

+

The process routine of a PVRecord can access other PVRecords in two ways:

+
+
Directly accessing local pvDatabase
+
+ If the other PVRecord is accessed via the master PVDatabase then + threading issues are up to the implementation. + For now this method will not be discussed.
+
Access via pvAccess
+
+ If access is via pvAccess then locking is handled by pvAccess.
+
+

Access via pvAccess can be done either by local or remote channel provider.

+
+
+
Access via channelProviderLocal
+
+ If the local pvAccess server is used the implementation must be careful that it does not + caused deadlocks. + When the process method is called the pvRecord for the process method is locked. + When it makes a pvAccess get, put, etc request the other record is locked. + Thus if a set of pvAccess links are implemented the possibility of deadlocks + exists. A simple example is two records that have links to each other. + More complex sets are easily created. + Unless the developer has complete control of the set of records then remote pvAccess should + be used. + But this results in more context switches. +
+
Access via remote pvAccess
+
If remote pvAccess is used then all lockimg issues are handled by pvAccess. + The linked channel can be a pvRecord in the local pvDatabase or can be implemented + by a remote pvAccess server.
+
+

Data synchronization

+

If pvAccess is used then it handles data synchronization. +This is done by making a copy of the data that is transfered between the two pvRecords. +This is true if either remote or local pvAccess is used. +Each get, put, etc request results in data being copied between the two records.

+

+If the linked channel is a local pvRecord then, +for scalar and structure arrays, +raw data is NOT copied for gets. +This is because pvData uses shared_vector to hold the raw data. +Instead of copying the raw data the reference count is incremented.

+

For puts the linked array will force a new allocation of the raw data in the linked record, +i. e. copy on write semantics are enforced. This is done automatically +by pvData and not by pvDatabase.

+

Some details

+

As mentioned before a pvDatabase server can be either a separate process, +i. e. a main program, or can be part of a V3IOC.

+

A main pvDatabase server issues the following calls:

+
+ ClientFactory::start();
+ ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
+ ...
+ ServerContext::shared_pointer serverContext = startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
+
+

The first call is only necessary if some of the pvRecords +have pvAccess links. +These must be called before any code that uses links is initialized. +After these two calls there will be two channel providers: local, and pvAccess. +

+

A pvDatabase that is part of a V3IOC has the following in the st.cmd file.

+
+...
+iocInit()
+startPVAClient
+startPVAServer
+## commands to create pvRecords
+
+

+Once the client and local provider code has started then the following creates a channel access link. +

+
+PVDatabasePtr master = PVDatabase::getMaster();
+ChannelAccess::shared_pointer channelAccess = getChannelAccess();
+ChannelProvider::shared_pointer provider = channelAccess->getProvider(providerName);
+Channel::shared_pointer channel = provider->createChannel(channelName,channelRequester);
+
+

examplePowerSupply

+
+
powerSupplyRecordTest.h
+
+ This provides code that simulates a power supply. + It computes the current from the voltage and power. + It is used for testing. + The complete implementation is provided in the header file. + Thus code will be generated only if other code includes the + header file and creates a record instance. +
+
+

powerSupplyRecordTest

+

This simulates a simple power supply record. +It is used for testing.

Array Performance and Memory Example

This section describes main programs that demonstrate performance of large arrays and can also be used to check for memory leaks. diff --git a/exampleDatabase/Makefile b/exampleDatabase/Makefile new file mode 100644 index 0000000..db71505 --- /dev/null +++ b/exampleDatabase/Makefile @@ -0,0 +1,16 @@ +#Makefile at top of application tree +TOP = . +include $(TOP)/configure/CONFIG +DIRS += configure + +DIRS += src +src_DEPEND_DIRS = configure + +DIRS += example +test_DEPEND_DIRS = src + +DIRS += iocBoot + +include $(TOP)/configure/RULES_TOP + + diff --git a/exampleDatabase/configure/CONFIG b/exampleDatabase/configure/CONFIG new file mode 100644 index 0000000..c1a4703 --- /dev/null +++ b/exampleDatabase/configure/CONFIG @@ -0,0 +1,29 @@ +# CONFIG - Load build configuration data +# +# Do not make changes to this file! + +# Allow user to override where the build rules come from +RULES = $(EPICS_BASE) + +# RELEASE files point to other application tops +include $(TOP)/configure/RELEASE +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common +ifdef T_A +-include $(TOP)/configure/RELEASE.Common.$(T_A) +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) +endif + +CONFIG = $(RULES)/configure +include $(CONFIG)/CONFIG + +# Override the Base definition: +INSTALL_LOCATION = $(TOP) + +# CONFIG_SITE files contain other build configuration settings +include $(TOP)/configure/CONFIG_SITE +-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common +ifdef T_A + -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) + -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) +endif + diff --git a/exampleDatabase/configure/CONFIG_SITE b/exampleDatabase/configure/CONFIG_SITE new file mode 100644 index 0000000..9e1ec9a --- /dev/null +++ b/exampleDatabase/configure/CONFIG_SITE @@ -0,0 +1,39 @@ +# CONFIG_SITE + +# Make any application-specific changes to the EPICS build +# configuration variables in this file. +# +# Host/target specific settings can be specified in files named +# CONFIG_SITE.$(EPICS_HOST_ARCH).Common +# CONFIG_SITE.Common.$(T_A) +# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) + +# CHECK_RELEASE controls the consistency checking of the support +# applications pointed to by the RELEASE* files. +# Normally CHECK_RELEASE should be set to YES. +# Set CHECK_RELEASE to NO to disable checking completely. +# Set CHECK_RELEASE to WARN to perform consistency checking but +# continue building anyway if conflicts are found. +#CHECK_RELEASE = YES + +# Set this when you only want to compile this application +# for a subset of the cross-compiled target architectures +# that Base is built for. +#CROSS_COMPILER_TARGET_ARCHS = vxWorks-68040 + +# To install files into a location other than $(TOP) define +# INSTALL_LOCATION here. +#INSTALL_LOCATION= + +# Set this when your IOC and the host use different paths +# to access the application. This will be needed to boot +# from a Microsoft FTP server or with some NFS mounts. +# You must rebuild in the iocBoot directory for this to +# take effect. +#IOCS_APPL_TOP = + +INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv +USR_INCLUDES += -I $(INSTALL_LOCATION)/include + +-include $(TOP)/configure/CONFIG_SITE.local +-include $(TOP)/../CONFIG.local diff --git a/exampleLink/configure/RELEASE.local b/exampleDatabase/configure/ExampleRELEASE.local similarity index 100% rename from exampleLink/configure/RELEASE.local rename to exampleDatabase/configure/ExampleRELEASE.local diff --git a/exampleDatabase/configure/Makefile b/exampleDatabase/configure/Makefile new file mode 100644 index 0000000..9254309 --- /dev/null +++ b/exampleDatabase/configure/Makefile @@ -0,0 +1,8 @@ +TOP=.. + +include $(TOP)/configure/CONFIG + +TARGETS = $(CONFIG_TARGETS) +CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) + +include $(TOP)/configure/RULES diff --git a/exampleDatabase/configure/RELEASE b/exampleDatabase/configure/RELEASE new file mode 100644 index 0000000..15c3090 --- /dev/null +++ b/exampleDatabase/configure/RELEASE @@ -0,0 +1,44 @@ +# RELEASE - Location of external support modules +# +# IF YOU MAKE ANY CHANGES to this file you must subsequently +# do a "gnumake rebuild" in this application's top level +# directory. +# +# The build process does not check dependencies against files +# that are outside this application, thus you should do a +# "gnumake rebuild" in the top level directory after EPICS_BASE +# or any other external module pointed to below is rebuilt. +# +# Host- or target-specific settings can be given in files named +# RELEASE.$(EPICS_HOST_ARCH).Common +# RELEASE.Common.$(T_A) +# RELEASE.$(EPICS_HOST_ARCH).$(T_A) +# +# This file should ONLY define paths to other support modules, +# or include statements that pull in similar RELEASE files. +# Build settings that are NOT module paths should appear in a +# CONFIG_SITE file. + +TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top + +# If using the sequencer, point SNCSEQ at its top directory: +#SNCSEQ=$(EPICS_BASE)/../modules/soft/seq + +# EPICS_BASE usually appears last so other apps can override stuff: + +# do not edit the locations in this file +# create RELEASE.local with the paths to your EPICS_BASE, PVDATA, and PVACCESS +# these default locations are needed for the BNL Jenkins server to work + +# Set RULES here if you want to take build rules from somewhere +# other than EPICS_BASE: +#RULES=/path/to/epics/support/module/rules/x-y + +# Leave these in for the Jenkins build at BNL to work +EPICS_BASE=/home/install/epics/base +PVDATA=/home/mrk/hg/pvDataCPP +PVACCESS=/home/mrk/hg/pvAccessCPP + +# set your EPICS_BASE, PVDATA and PVACCESS paths in here +-include $(TOP)/../RELEASE.local +-include $(TOP)/configure/RELEASE.local diff --git a/exampleDatabase/configure/RULES b/exampleDatabase/configure/RULES new file mode 100644 index 0000000..6d56e14 --- /dev/null +++ b/exampleDatabase/configure/RULES @@ -0,0 +1,6 @@ +# RULES + +include $(CONFIG)/RULES + +# Library should be rebuilt because LIBOBJS may have changed. +$(LIBNAME): ../Makefile diff --git a/exampleDatabase/configure/RULES.ioc b/exampleDatabase/configure/RULES.ioc new file mode 100644 index 0000000..901987c --- /dev/null +++ b/exampleDatabase/configure/RULES.ioc @@ -0,0 +1,2 @@ +#RULES.ioc +include $(CONFIG)/RULES.ioc diff --git a/exampleDatabase/configure/RULES_DIRS b/exampleDatabase/configure/RULES_DIRS new file mode 100644 index 0000000..3ba269d --- /dev/null +++ b/exampleDatabase/configure/RULES_DIRS @@ -0,0 +1,2 @@ +#RULES_DIRS +include $(CONFIG)/RULES_DIRS diff --git a/exampleDatabase/configure/RULES_TOP b/exampleDatabase/configure/RULES_TOP new file mode 100644 index 0000000..d09d668 --- /dev/null +++ b/exampleDatabase/configure/RULES_TOP @@ -0,0 +1,3 @@ +#RULES_TOP +include $(CONFIG)/RULES_TOP + diff --git a/exampleDatabase/example/Db/Makefile b/exampleDatabase/example/Db/Makefile new file mode 100644 index 0000000..1e9fd60 --- /dev/null +++ b/exampleDatabase/example/Db/Makefile @@ -0,0 +1,28 @@ +TOP=../.. +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS AFTER THIS LINE + +#---------------------------------------------------- +# Optimization of db files using dbst (DEFAULT: NO) +#DB_OPT = YES + +#---------------------------------------------------- +# Create and install (or just install) +# databases, templates, substitutions like this +DB += dbScalar.db +DB += dbInteger.db +DB += dbArray.db +DB += dbString.db +DB += dbStringArray.db +DB += dbEnum.db +DB += dbCounter.db + +#---------------------------------------------------- +# If .db template is not named *.template add +# _TEMPLATE = + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/exampleDatabase/example/Db/dbArray.db b/exampleDatabase/example/Db/dbArray.db new file mode 100644 index 0000000..76506a7 --- /dev/null +++ b/exampleDatabase/example/Db/dbArray.db @@ -0,0 +1,9 @@ +record(waveform, "$(name)") +{ + field(NELM,"5") + field(NORD,"5") + field(FTVL,"$(type)") + field(EGU, "Counts") + field(HOPR, "10") + field(LOPR, "0") +} diff --git a/exampleDatabase/example/Db/dbCounter.db b/exampleDatabase/example/Db/dbCounter.db new file mode 100644 index 0000000..06aec31 --- /dev/null +++ b/exampleDatabase/example/Db/dbCounter.db @@ -0,0 +1,20 @@ +record(calc, "${name}") +{ + field(DESC, "Counter") + field(SCAN,"1 second") + field(CALC, "(A_registerRecordDeviceDriver.cpp will be created from .dbd +exampleDatabase_SRCS += exampleDatabase_registerRecordDeviceDriver.cpp +exampleDatabase_SRCS_DEFAULT += exampleDatabaseMain.cpp +exampleDatabase_SRCS_vxWorks += -nil- + + +# The following adds support from base/src/vxWorks +exampleDatabase_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary + +exampleDatabase_LIBS += pvData pvAccess +exampleDatabase_LIBS += pvDatabase +exampleDatabase_LIBS += pvaSrv +exampleDatabase_LIBS += exampleDatabase +exampleDatabase_LIBS += $(EPICS_BASE_IOC_LIBS) + +#=========================== + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/exampleDatabase/example/src/exampleDatabaseInclude.dbd b/exampleDatabase/example/src/exampleDatabaseInclude.dbd new file mode 100644 index 0000000..6c8005a --- /dev/null +++ b/exampleDatabase/example/src/exampleDatabaseInclude.dbd @@ -0,0 +1,3 @@ +include "base.dbd" +include "PVAServerRegister.dbd" +registrar("exampleDatabaseRegister") diff --git a/exampleDatabase/example/src/exampleDatabaseMain.cpp b/exampleDatabase/example/src/exampleDatabaseMain.cpp new file mode 100644 index 0000000..18f528f --- /dev/null +++ b/exampleDatabase/example/src/exampleDatabaseMain.cpp @@ -0,0 +1,57 @@ +/*exampleDatabaseMain.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace std; +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pvDatabase; + + +int main(int argc,char *argv[]) +{ + PVDatabasePtr master = PVDatabase::getMaster(); + ChannelProviderLocalPtr channelProvider = getChannelProviderLocal(); + ExampleDatabase::create(); + ServerContext::shared_pointer ctx = + startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true); + cout << "exampleDatabase\n"; + PVStringArrayPtr pvNames = master->getRecordNames(); + String buffer; + pvNames->toString(&buffer); + cout << "recordNames" << endl << buffer << endl; + string str; + while(true) { + cout << "Type exit to stop: \n"; + getline(cin,str); + if(str.compare("exit")==0) break; + + } + ctx->destroy(); + epicsThreadSleep(1.0); + channelProvider->destroy(); + return 0; +} + diff --git a/exampleDatabase/iocBoot/Makefile b/exampleDatabase/iocBoot/Makefile new file mode 100644 index 0000000..b6d6f07 --- /dev/null +++ b/exampleDatabase/iocBoot/Makefile @@ -0,0 +1,7 @@ +TOP = .. +include $(TOP)/configure/CONFIG +DIRS += $(wildcard *ioc*) +DIRS += $(wildcard as*) +DIRS += $(wildcard example*) +include $(EPICS_BASE)/configure/RULES_DIRS + diff --git a/exampleDatabase/iocBoot/exampleDatabase/Makefile b/exampleDatabase/iocBoot/exampleDatabase/Makefile new file mode 100644 index 0000000..e1b9aa4 --- /dev/null +++ b/exampleDatabase/iocBoot/exampleDatabase/Makefile @@ -0,0 +1,5 @@ +TOP = ../.. +include $(TOP)/configure/CONFIG +ARCH = $(EPICS_HOST_ARCH) +TARGETS = envPaths +include $(TOP)/configure/RULES.ioc diff --git a/exampleDatabase/iocBoot/exampleDatabase/st.cmd b/exampleDatabase/iocBoot/exampleDatabase/st.cmd new file mode 100644 index 0000000..5266a7b --- /dev/null +++ b/exampleDatabase/iocBoot/exampleDatabase/st.cmd @@ -0,0 +1,21 @@ +< envPaths + +cd ${TOP} + +## Register all support components +dbLoadDatabase("dbd/exampleDatabase.dbd") +exampleDatabase_registerRecordDeviceDriver(pdbbase) + +## Load record instances +dbLoadRecords("db/dbScalar.db","name=double01,type=ao") +dbLoadRecords("db/dbStringArray.db","name=stringArray01") +dbLoadRecords("db/dbEnum.db","name=enum01") +dbLoadRecords("db/dbCounter.db","name=counter01"); + +cd ${TOP}/iocBoot/${IOC} +iocInit() +dbl +epicsThreadSleep(2.0) +exampleDatabase +startPVAServer +pvdbl diff --git a/exampleDatabase/src/Makefile b/exampleDatabase/src/Makefile new file mode 100644 index 0000000..d6c3ed3 --- /dev/null +++ b/exampleDatabase/src/Makefile @@ -0,0 +1,38 @@ +TOP=.. + +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS AFTER THIS LINE +#============================= + +#================================================== +# Build an IOC support library +# + + +PROD_HOST += exampleDatabaseMain +exampleDatabaseMain_SRCS += exampleDatabaseMain.cpp +exampleDatabaseMain_LIBS += Com +exampleDatabaseMain_LIBS += pvData +exampleDatabaseMain_LIBS += pvAccess +exampleDatabaseMain_LIBS += pvDatabase +exampleDatabaseMain_LIBS += exampleDatabase + +DBD += exampleDatabase.dbd + +INC += exampleDatabase.h + +LIBRARY_IOC += exampleDatabase +exampleDatabase_SRCS += exampleDatabase.cpp +exampleDatabase_SRCS += exampleDatabaseRegister.cpp +exampleDatabase_LIBS += pvData +exampleDatabase_LIBS += pvAccess +exampleDatabase_LIBS += pvDatabase +exampleDatabase_LIBS += $(EPICS_BASE_IOC_LIBS) + +#=========================== + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/exampleDatabase/src/exampleDatabase.cpp b/exampleDatabase/src/exampleDatabase.cpp new file mode 100644 index 0000000..cff4f5f --- /dev/null +++ b/exampleDatabase/src/exampleDatabase.cpp @@ -0,0 +1,138 @@ +/*exampleDatabase.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2013.07.24 + */ + +/* Author: Marty Kraimer */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pvDatabase; + +static FieldCreatePtr fieldCreate = getFieldCreate(); +static StandardFieldPtr standardField = getStandardField(); +static PVDataCreatePtr pvDataCreate = getPVDataCreate(); +static StandardPVFieldPtr standardPVField = getStandardPVField(); + +static PVStructurePtr createPowerSupply() +{ + size_t nfields = 5; + StringArray names; + names.reserve(nfields); + FieldConstPtrArray powerSupply; + powerSupply.reserve(nfields); + names.push_back("alarm"); + powerSupply.push_back(standardField->alarm()); + names.push_back("timeStamp"); + powerSupply.push_back(standardField->timeStamp()); + String properties("alarm,display"); + names.push_back("voltage"); + powerSupply.push_back(standardField->scalar(pvDouble,properties)); + names.push_back("power"); + powerSupply.push_back(standardField->scalar(pvDouble,properties)); + names.push_back("current"); + powerSupply.push_back(standardField->scalar(pvDouble,properties)); + return pvDataCreate->createPVStructure( + fieldCreate->createStructure(names,powerSupply)); +} + +static void createStructureArrayRecord( + PVDatabasePtr const &master, + ScalarType scalarType, + String const &recordName) +{ + StructureConstPtr structure = standardField->scalar( + pvDouble, + String("value,alarm,timeStamp")); + StringArray names(2); + FieldConstPtrArray fields(2); + names[0] = "timeStamp"; + names[1] = "value"; + fields[0] = standardField->timeStamp(); + fields[1] = fieldCreate->createStructureArray(structure); + StructureConstPtr top = fieldCreate->createStructure(names,fields); + PVStructurePtr pvStructure = pvDataCreate->createPVStructure(top); + PVRecordPtr pvRecord = PVRecord::create(recordName,pvStructure); + bool result = master->addRecord(pvRecord); + if(!result) cout<< "record " << recordName << " not added" << endl; +} + +static void createRecords( + PVDatabasePtr const &master, + ScalarType scalarType, + String const &recordNamePrefix, + String const &properties) +{ + String recordName = recordNamePrefix; + PVStructurePtr pvStructure = standardPVField->scalar(scalarType,properties); + PVRecordPtr pvRecord = PVRecord::create(recordName,pvStructure); + bool result = master->addRecord(pvRecord); + if(!result) cout<< "record " << recordName << " not added" << endl; + recordName += "Array"; + pvStructure = standardPVField->scalarArray(scalarType,properties); + pvRecord = PVRecord::create(recordName,pvStructure); + result = master->addRecord(pvRecord); +} + +void ExampleDatabase::create() +{ + PVDatabasePtr master = PVDatabase::getMaster(); + PVRecordPtr pvRecord; + String recordName; + bool result(false); + recordName = "traceRecordPGRPC"; + pvRecord = TraceRecord::create(recordName); + result = master->addRecord(pvRecord); + if(!result) cout<< "record " << recordName << " not added" << endl; + String properties; + properties = "alarm,timeStamp"; + createRecords(master,pvBoolean,"exampleBoolean",properties); + createRecords(master,pvByte,"exampleByte",properties); + createRecords(master,pvShort,"exampleShort",properties); + createRecords(master,pvInt,"exampleInt",properties); + createRecords(master,pvLong,"exampleLong",properties); + createRecords(master,pvFloat,"exampleFloat",properties); + createRecords(master,pvDouble,"exampleDouble",properties); + createRecords(master,pvString,"exampleString",properties); + createStructureArrayRecord(master,pvDouble,"exampleStructureArray"); + recordName = "examplePowerSupply"; + PVStructurePtr pvStructure = createPowerSupply(); + PowerSupplyRecordTestPtr psr = + PowerSupplyRecordTest::create(recordName,pvStructure); + if(psr.get()==NULL) { + cout << "PowerSupplyRecordTest::create failed" << endl; + return; + } + result = master->addRecord(psr); + if(!result) cout<< "record " << recordName << " not added" << endl; + recordName = "laptoprecordListPGRPC"; + pvRecord = RecordListRecord::create(recordName); + result = master->addRecord(pvRecord); + if(!result) cout<< "record " << recordName << " not added" << endl; +} + diff --git a/exampleDatabase/src/exampleDatabase.h b/exampleDatabase/src/exampleDatabase.h new file mode 100644 index 0000000..f26080d --- /dev/null +++ b/exampleDatabase/src/exampleDatabase.h @@ -0,0 +1,27 @@ +/* exampleDatabase.h */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2013.07.24 + */ +#ifndef EXAMPLEDATABASE_H +#define EXAMPLEDATABASE_H + + +#include + +namespace epics { namespace pvDatabase { + +class ExampleDatabase{ +public: + static void create(); +}; + + +}} + +#endif /* EXAMPLEDATABASE_H */ diff --git a/exampleDatabase/src/exampleDatabaseInclude.dbd b/exampleDatabase/src/exampleDatabaseInclude.dbd new file mode 100644 index 0000000..d1f734b --- /dev/null +++ b/exampleDatabase/src/exampleDatabaseInclude.dbd @@ -0,0 +1 @@ +registrar("exampleDatabaseRegister") diff --git a/exampleDatabase/src/exampleDatabaseMain.cpp b/exampleDatabase/src/exampleDatabaseMain.cpp new file mode 100644 index 0000000..14164be --- /dev/null +++ b/exampleDatabase/src/exampleDatabaseMain.cpp @@ -0,0 +1,60 @@ +/*exampleDatabaseMain.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace std; +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pvDatabase; + + +int main(int argc,char *argv[]) +{ + PVDatabasePtr master = PVDatabase::getMaster(); + ChannelProviderLocalPtr channelProvider = getChannelProviderLocal(); + ExampleDatabase::create(); + ServerContext::shared_pointer ctx = + startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true); + cout << "exampleDatabase\n"; + PVStringArrayPtr pvNames = master->getRecordNames(); + String buffer; + pvNames->toString(&buffer); + cout << "recordNames" << endl << buffer << endl; + PVRecordPtr pvRecord = master->findRecord("laptoprecordListPGRPC"); + PVStructurePtr pvStructure = pvRecord->getPVRecordStructure()->getPVStructure(); + cout << "PVStructure" << endl << pvStructure->dumpValue(cout) << endl; + string str; + while(true) { + cout << "Type exit to stop: \n"; + getline(cin,str); + if(str.compare("exit")==0) break; + + } + ctx->destroy(); + epicsThreadSleep(1.0); + channelProvider->destroy(); + return 0; +} + diff --git a/exampleDatabase/src/exampleDatabaseRegister.cpp b/exampleDatabase/src/exampleDatabaseRegister.cpp new file mode 100644 index 0000000..10e4068 --- /dev/null +++ b/exampleDatabase/src/exampleDatabaseRegister.cpp @@ -0,0 +1,60 @@ +/*exampleDatabase.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2013.07.24 + */ + + +/* Author: Marty Kraimer */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pvDatabase; + +static const iocshArg testArg0 = { "prefix", iocshArgString }; +static const iocshArg *testArgs[] = { + &testArg0}; + +static const iocshFuncDef exampleDatabaseFuncDef = { + "exampleDatabase", 1, testArgs}; +static void exampleDatabaseCallFunc(const iocshArgBuf *args) +{ + ExampleDatabase::create(); +} + +static void exampleDatabaseRegister(void) +{ + static int firstTime = 1; + if (firstTime) { + firstTime = 0; + iocshRegister(&exampleDatabaseFuncDef, exampleDatabaseCallFunc); + } +} +epicsExportRegistrar(exampleDatabaseRegister); diff --git a/exampleLink/configure/ExampleRELEASE.local b/exampleLink/configure/ExampleRELEASE.local new file mode 100644 index 0000000..95e3783 --- /dev/null +++ b/exampleLink/configure/ExampleRELEASE.local @@ -0,0 +1,8 @@ +EPICS_BASE=/home/install/epics/base +TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top +EPICSV4HOME=/home/hg +PVCOMMON=${EPICSV4HOME}/pvCommonCPP +PVDATA=${EPICSV4HOME}/pvDataCPP +PVACCESS=${EPICSV4HOME}/pvAccessCPP +PVDATABASE=${EPICSV4HOME}/pvDatabaseCPP +PVASRV=${EPICSV4HOME}/pvaSrv diff --git a/examplePowerSupply/Makefile b/examplePowerSupply/Makefile new file mode 100644 index 0000000..db71505 --- /dev/null +++ b/examplePowerSupply/Makefile @@ -0,0 +1,16 @@ +#Makefile at top of application tree +TOP = . +include $(TOP)/configure/CONFIG +DIRS += configure + +DIRS += src +src_DEPEND_DIRS = configure + +DIRS += example +test_DEPEND_DIRS = src + +DIRS += iocBoot + +include $(TOP)/configure/RULES_TOP + + diff --git a/examplePowerSupply/configure/CONFIG b/examplePowerSupply/configure/CONFIG new file mode 100644 index 0000000..c1a4703 --- /dev/null +++ b/examplePowerSupply/configure/CONFIG @@ -0,0 +1,29 @@ +# CONFIG - Load build configuration data +# +# Do not make changes to this file! + +# Allow user to override where the build rules come from +RULES = $(EPICS_BASE) + +# RELEASE files point to other application tops +include $(TOP)/configure/RELEASE +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common +ifdef T_A +-include $(TOP)/configure/RELEASE.Common.$(T_A) +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) +endif + +CONFIG = $(RULES)/configure +include $(CONFIG)/CONFIG + +# Override the Base definition: +INSTALL_LOCATION = $(TOP) + +# CONFIG_SITE files contain other build configuration settings +include $(TOP)/configure/CONFIG_SITE +-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common +ifdef T_A + -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) + -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) +endif + diff --git a/examplePowerSupply/configure/CONFIG_SITE b/examplePowerSupply/configure/CONFIG_SITE new file mode 100644 index 0000000..9e1ec9a --- /dev/null +++ b/examplePowerSupply/configure/CONFIG_SITE @@ -0,0 +1,39 @@ +# CONFIG_SITE + +# Make any application-specific changes to the EPICS build +# configuration variables in this file. +# +# Host/target specific settings can be specified in files named +# CONFIG_SITE.$(EPICS_HOST_ARCH).Common +# CONFIG_SITE.Common.$(T_A) +# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) + +# CHECK_RELEASE controls the consistency checking of the support +# applications pointed to by the RELEASE* files. +# Normally CHECK_RELEASE should be set to YES. +# Set CHECK_RELEASE to NO to disable checking completely. +# Set CHECK_RELEASE to WARN to perform consistency checking but +# continue building anyway if conflicts are found. +#CHECK_RELEASE = YES + +# Set this when you only want to compile this application +# for a subset of the cross-compiled target architectures +# that Base is built for. +#CROSS_COMPILER_TARGET_ARCHS = vxWorks-68040 + +# To install files into a location other than $(TOP) define +# INSTALL_LOCATION here. +#INSTALL_LOCATION= + +# Set this when your IOC and the host use different paths +# to access the application. This will be needed to boot +# from a Microsoft FTP server or with some NFS mounts. +# You must rebuild in the iocBoot directory for this to +# take effect. +#IOCS_APPL_TOP = + +INSTALL_INCLUDE = $(INSTALL_LOCATION)/include/pv +USR_INCLUDES += -I $(INSTALL_LOCATION)/include + +-include $(TOP)/configure/CONFIG_SITE.local +-include $(TOP)/../CONFIG.local diff --git a/examplePowerSupply/configure/ExampleRELEASE.local b/examplePowerSupply/configure/ExampleRELEASE.local new file mode 100644 index 0000000..95e3783 --- /dev/null +++ b/examplePowerSupply/configure/ExampleRELEASE.local @@ -0,0 +1,8 @@ +EPICS_BASE=/home/install/epics/base +TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top +EPICSV4HOME=/home/hg +PVCOMMON=${EPICSV4HOME}/pvCommonCPP +PVDATA=${EPICSV4HOME}/pvDataCPP +PVACCESS=${EPICSV4HOME}/pvAccessCPP +PVDATABASE=${EPICSV4HOME}/pvDatabaseCPP +PVASRV=${EPICSV4HOME}/pvaSrv diff --git a/examplePowerSupply/configure/Makefile b/examplePowerSupply/configure/Makefile new file mode 100644 index 0000000..9254309 --- /dev/null +++ b/examplePowerSupply/configure/Makefile @@ -0,0 +1,8 @@ +TOP=.. + +include $(TOP)/configure/CONFIG + +TARGETS = $(CONFIG_TARGETS) +CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) + +include $(TOP)/configure/RULES diff --git a/examplePowerSupply/configure/RELEASE b/examplePowerSupply/configure/RELEASE new file mode 100644 index 0000000..15c3090 --- /dev/null +++ b/examplePowerSupply/configure/RELEASE @@ -0,0 +1,44 @@ +# RELEASE - Location of external support modules +# +# IF YOU MAKE ANY CHANGES to this file you must subsequently +# do a "gnumake rebuild" in this application's top level +# directory. +# +# The build process does not check dependencies against files +# that are outside this application, thus you should do a +# "gnumake rebuild" in the top level directory after EPICS_BASE +# or any other external module pointed to below is rebuilt. +# +# Host- or target-specific settings can be given in files named +# RELEASE.$(EPICS_HOST_ARCH).Common +# RELEASE.Common.$(T_A) +# RELEASE.$(EPICS_HOST_ARCH).$(T_A) +# +# This file should ONLY define paths to other support modules, +# or include statements that pull in similar RELEASE files. +# Build settings that are NOT module paths should appear in a +# CONFIG_SITE file. + +TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top + +# If using the sequencer, point SNCSEQ at its top directory: +#SNCSEQ=$(EPICS_BASE)/../modules/soft/seq + +# EPICS_BASE usually appears last so other apps can override stuff: + +# do not edit the locations in this file +# create RELEASE.local with the paths to your EPICS_BASE, PVDATA, and PVACCESS +# these default locations are needed for the BNL Jenkins server to work + +# Set RULES here if you want to take build rules from somewhere +# other than EPICS_BASE: +#RULES=/path/to/epics/support/module/rules/x-y + +# Leave these in for the Jenkins build at BNL to work +EPICS_BASE=/home/install/epics/base +PVDATA=/home/mrk/hg/pvDataCPP +PVACCESS=/home/mrk/hg/pvAccessCPP + +# set your EPICS_BASE, PVDATA and PVACCESS paths in here +-include $(TOP)/../RELEASE.local +-include $(TOP)/configure/RELEASE.local diff --git a/examplePowerSupply/configure/RULES b/examplePowerSupply/configure/RULES new file mode 100644 index 0000000..6d56e14 --- /dev/null +++ b/examplePowerSupply/configure/RULES @@ -0,0 +1,6 @@ +# RULES + +include $(CONFIG)/RULES + +# Library should be rebuilt because LIBOBJS may have changed. +$(LIBNAME): ../Makefile diff --git a/examplePowerSupply/configure/RULES.ioc b/examplePowerSupply/configure/RULES.ioc new file mode 100644 index 0000000..901987c --- /dev/null +++ b/examplePowerSupply/configure/RULES.ioc @@ -0,0 +1,2 @@ +#RULES.ioc +include $(CONFIG)/RULES.ioc diff --git a/examplePowerSupply/configure/RULES_DIRS b/examplePowerSupply/configure/RULES_DIRS new file mode 100644 index 0000000..3ba269d --- /dev/null +++ b/examplePowerSupply/configure/RULES_DIRS @@ -0,0 +1,2 @@ +#RULES_DIRS +include $(CONFIG)/RULES_DIRS diff --git a/examplePowerSupply/configure/RULES_TOP b/examplePowerSupply/configure/RULES_TOP new file mode 100644 index 0000000..d09d668 --- /dev/null +++ b/examplePowerSupply/configure/RULES_TOP @@ -0,0 +1,3 @@ +#RULES_TOP +include $(CONFIG)/RULES_TOP + diff --git a/examplePowerSupply/example/Db/Makefile b/examplePowerSupply/example/Db/Makefile new file mode 100644 index 0000000..1e9fd60 --- /dev/null +++ b/examplePowerSupply/example/Db/Makefile @@ -0,0 +1,28 @@ +TOP=../.. +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS AFTER THIS LINE + +#---------------------------------------------------- +# Optimization of db files using dbst (DEFAULT: NO) +#DB_OPT = YES + +#---------------------------------------------------- +# Create and install (or just install) +# databases, templates, substitutions like this +DB += dbScalar.db +DB += dbInteger.db +DB += dbArray.db +DB += dbString.db +DB += dbStringArray.db +DB += dbEnum.db +DB += dbCounter.db + +#---------------------------------------------------- +# If .db template is not named *.template add +# _TEMPLATE = + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/examplePowerSupply/example/Db/dbArray.db b/examplePowerSupply/example/Db/dbArray.db new file mode 100644 index 0000000..76506a7 --- /dev/null +++ b/examplePowerSupply/example/Db/dbArray.db @@ -0,0 +1,9 @@ +record(waveform, "$(name)") +{ + field(NELM,"5") + field(NORD,"5") + field(FTVL,"$(type)") + field(EGU, "Counts") + field(HOPR, "10") + field(LOPR, "0") +} diff --git a/examplePowerSupply/example/Db/dbCounter.db b/examplePowerSupply/example/Db/dbCounter.db new file mode 100644 index 0000000..06aec31 --- /dev/null +++ b/examplePowerSupply/example/Db/dbCounter.db @@ -0,0 +1,20 @@ +record(calc, "${name}") +{ + field(DESC, "Counter") + field(SCAN,"1 second") + field(CALC, "(A_registerRecordDeviceDriver.cpp will be created from .dbd +powerSupply_SRCS += powerSupply_registerRecordDeviceDriver.cpp +powerSupply_SRCS_DEFAULT += powerSupplyMain.cpp +powerSupply_SRCS_vxWorks += -nil- + + +# The following adds support from base/src/vxWorks +powerSupply_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary + +powerSupply_LIBS += pvData pvAccess +powerSupply_LIBS += pvDatabase +powerSupply_LIBS += pvaSrv +powerSupply_LIBS += powerSupply +powerSupply_LIBS += $(EPICS_BASE_IOC_LIBS) + +#=========================== + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/examplePowerSupply/example/src/powerSupplyInclude.dbd b/examplePowerSupply/example/src/powerSupplyInclude.dbd new file mode 100644 index 0000000..914302e --- /dev/null +++ b/examplePowerSupply/example/src/powerSupplyInclude.dbd @@ -0,0 +1,5 @@ +include "base.dbd" +include "PVAServerRegister.dbd" +include "registerChannelProviderLocal.dbd" +include "dbPv.dbd" +include "powerSupply.dbd" diff --git a/examplePowerSupply/example/src/powerSupplyMain.cpp b/examplePowerSupply/example/src/powerSupplyMain.cpp new file mode 100644 index 0000000..f7c1208 --- /dev/null +++ b/examplePowerSupply/example/src/powerSupplyMain.cpp @@ -0,0 +1,31 @@ +/* powerSupplyMain.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2013.07.24 + */ + +#include +#include +#include +#include +#include + +#include "epicsExit.h" +#include "epicsThread.h" +#include "iocsh.h" + +int main(int argc,char *argv[]) +{ + if(argc>=2) { + iocsh(argv[1]); + epicsThreadSleep(.2); + } + iocsh(NULL); + epicsExit(0); + return(0); +} diff --git a/examplePowerSupply/iocBoot/Makefile b/examplePowerSupply/iocBoot/Makefile new file mode 100644 index 0000000..cd7d357 --- /dev/null +++ b/examplePowerSupply/iocBoot/Makefile @@ -0,0 +1,7 @@ +TOP = .. +include $(TOP)/configure/CONFIG +DIRS += $(wildcard *ioc*) +DIRS += $(wildcard as*) +DIRS += $(wildcard power*) +include $(EPICS_BASE)/configure/RULES_DIRS + diff --git a/examplePowerSupply/iocBoot/powerSupply/Makefile b/examplePowerSupply/iocBoot/powerSupply/Makefile new file mode 100644 index 0000000..e1b9aa4 --- /dev/null +++ b/examplePowerSupply/iocBoot/powerSupply/Makefile @@ -0,0 +1,5 @@ +TOP = ../.. +include $(TOP)/configure/CONFIG +ARCH = $(EPICS_HOST_ARCH) +TARGETS = envPaths +include $(TOP)/configure/RULES.ioc diff --git a/examplePowerSupply/iocBoot/powerSupply/st.cmd b/examplePowerSupply/iocBoot/powerSupply/st.cmd new file mode 100644 index 0000000..b8388f4 --- /dev/null +++ b/examplePowerSupply/iocBoot/powerSupply/st.cmd @@ -0,0 +1,23 @@ +< envPaths + +cd ${TOP} + +## Register all support components +dbLoadDatabase("dbd/powerSupply.dbd") +powerSupply_registerRecordDeviceDriver(pdbbase) + +## Load record instances +dbLoadRecords("db/dbScalar.db","name=pvdouble,type=ao") +dbLoadRecords("db/dbArray.db","name=pvdoubleArray,type=DOUBLE") +dbLoadRecords("db/dbStringArray.db","name=pvstringArray") +dbLoadRecords("db/dbEnum.db","name=pvenum") +dbLoadRecords("db/dbCounter.db","name=pvcounter"); + +cd ${TOP}/iocBoot/${IOC} +iocInit() +dbl +epicsThreadSleep(1.0) +powerSupplyCreateRecord powerSupply +startPVAServer +pvdbl + diff --git a/examplePowerSupply/src/Makefile b/examplePowerSupply/src/Makefile new file mode 100644 index 0000000..d8880b6 --- /dev/null +++ b/examplePowerSupply/src/Makefile @@ -0,0 +1,38 @@ +TOP=.. + +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS AFTER THIS LINE +#============================= + +#================================================== +# Build an IOC support library +# + + +PROD_HOST += powerSupplyMain +powerSupplyMain_SRCS += powerSupplyMain.cpp +powerSupplyMain_LIBS += Com +powerSupplyMain_LIBS += pvData +powerSupplyMain_LIBS += pvAccess +powerSupplyMain_LIBS += pvDatabase +powerSupplyMain_LIBS += powerSupply + +DBD += powerSupply.dbd + +INC += powerSupply.h + +LIBRARY_IOC += powerSupply +powerSupply_SRCS += powerSupply.cpp +powerSupply_SRCS += powerSupplyRegister.cpp +powerSupply_LIBS += pvData +powerSupply_LIBS += pvAccess +powerSupply_LIBS += pvDatabase +powerSupply_LIBS += $(EPICS_BASE_IOC_LIBS) + +#=========================== + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/examplePowerSupply/src/powerSupply.cpp b/examplePowerSupply/src/powerSupply.cpp new file mode 100644 index 0000000..768a6af --- /dev/null +++ b/examplePowerSupply/src/powerSupply.cpp @@ -0,0 +1,179 @@ +/* powerSupply.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2013.04.02 + */ + +#include +#include +#include + +namespace epics { namespace pvDatabase { + +using namespace epics::pvData; + +PVStructurePtr createPowerSupply() +{ + FieldCreatePtr fieldCreate = getFieldCreate(); + StandardFieldPtr standardField = getStandardField(); + PVDataCreatePtr pvDataCreate = getPVDataCreate(); + + size_t nfields = 5; + StringArray names; + names.reserve(nfields); + FieldConstPtrArray powerSupply; + powerSupply.reserve(nfields); + names.push_back("alarm"); + powerSupply.push_back(standardField->alarm()); + names.push_back("timeStamp"); + powerSupply.push_back(standardField->timeStamp()); + String properties("alarm,display"); + names.push_back("voltage"); + powerSupply.push_back(standardField->scalar(pvDouble,properties)); + names.push_back("power"); + powerSupply.push_back(standardField->scalar(pvDouble,properties)); + names.push_back("current"); + powerSupply.push_back(standardField->scalar(pvDouble,properties)); + return pvDataCreate->createPVStructure( + fieldCreate->createStructure(names,powerSupply)); +} + +PowerSupplyPtr PowerSupply::create( + String const & recordName, + PVStructurePtr const & pvStructure) +{ + PowerSupplyPtr pvRecord( + new PowerSupply(recordName,pvStructure)); + if(!pvRecord->init()) pvRecord.reset(); + return pvRecord; +} + +PowerSupply::PowerSupply( + String const & recordName, + PVStructurePtr const & pvStructure) +: PVRecord(recordName,pvStructure) +{ +} + +PowerSupply::~PowerSupply() +{ +} + +void PowerSupply::destroy() +{ + PVRecord::destroy(); +} + +bool PowerSupply::init() +{ + initPVRecord(); + PVStructurePtr pvStructure = getPVStructure(); + PVFieldPtr pvField; + bool result; + pvField = pvStructure->getSubField("timeStamp"); + if(pvField.get()==NULL) { + std::cerr << "no timeStamp" << std::endl; + return false; + } + result = pvTimeStamp.attach(pvField); + if(!result) { + std::cerr << "no timeStamp" << std::endl; + return false; + } + pvField = pvStructure->getSubField("alarm"); + if(pvField.get()==NULL) { + std::cerr << "no alarm" << std::endl; + return false; + } + result = pvAlarm.attach(pvField); + if(!result) { + std::cerr << "no alarm" << std::endl; + return false; + } + String name; + name = "current.value"; + pvField = pvStructure->getSubField(name); + if(pvField.get()==NULL) { + name = "current"; + pvField = pvStructure->getSubField(name); + } + if(pvField.get()==NULL) { + std::cerr << "no current" << std::endl; + return false; + } + pvCurrent = pvStructure->getDoubleField(name); + if(pvCurrent.get()==NULL) return false; + name = "voltage.value"; + pvField = pvStructure->getSubField(name); + if(pvField.get()==NULL) { + name = "voltage"; + pvField = pvStructure->getSubField(name); + } + if(pvField.get()==NULL) { + std::cerr << "no voltage" << std::endl; + return false; + } + pvVoltage = pvStructure->getDoubleField(name); + if(pvVoltage.get()==NULL) return false; + name = "power.value"; + pvField = pvStructure->getSubField(name); + if(pvField.get()==NULL) { + name = "power"; + pvField = pvStructure->getSubField(name); + } + if(pvField.get()==NULL) { + std::cerr << "no power" << std::endl; + return false; + } + pvPower = pvStructure->getDoubleField(name); + if(pvPower.get()==NULL) return false; + return true; +} + +void PowerSupply::process() +{ + timeStamp.getCurrent(); + pvTimeStamp.set(timeStamp); + double voltage = pvVoltage->get(); + double power = pvPower->get(); + if(voltage<1e-3 && voltage>-1e-3) { + alarm.setMessage("bad voltage"); + alarm.setSeverity(majorAlarm); + pvAlarm.set(alarm); + return; + } + double current = power/voltage; + pvCurrent->put(current); + alarm.setMessage(""); + alarm.setSeverity(noAlarm); + pvAlarm.set(alarm); +} + +void PowerSupply::put(double power,double voltage) +{ + pvPower->put(power); + pvVoltage->put(voltage); +} + +double PowerSupply::getPower() +{ + return pvPower->get(); +} + +double PowerSupply::getVoltage() +{ + return pvVoltage->get(); +} + +double PowerSupply::getCurrent() +{ + return pvCurrent->get(); +} + + +}} diff --git a/examplePowerSupply/src/powerSupply.h b/examplePowerSupply/src/powerSupply.h new file mode 100644 index 0000000..fb98c49 --- /dev/null +++ b/examplePowerSupply/src/powerSupply.h @@ -0,0 +1,58 @@ +/* powerSupply.h */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2013.04.02 + */ +#ifndef POWERSUPPLY_H +#define POWERSUPPLY_H + +#include +#include +#include +#include +#include + +namespace epics { namespace pvDatabase { + +extern epics::pvData::PVStructurePtr createPowerSupply(); + +class PowerSupply; +typedef std::tr1::shared_ptr PowerSupplyPtr; + +class PowerSupply : + public PVRecord +{ +public: + POINTER_DEFINITIONS(PowerSupply); + static PowerSupplyPtr create( + epics::pvData::String const & recordName, + epics::pvData::PVStructurePtr const & pvStructure); + virtual ~PowerSupply(); + virtual void destroy(); + virtual bool init(); + virtual void process(); + void put(double power,double voltage); + double getPower(); + double getVoltage(); + double getCurrent(); +private: + PowerSupply(epics::pvData::String const & recordName, + epics::pvData::PVStructurePtr const & pvStructure); + epics::pvData::PVDoublePtr pvCurrent; + epics::pvData::PVDoublePtr pvPower; + epics::pvData::PVDoublePtr pvVoltage; + epics::pvData::PVAlarm pvAlarm; + epics::pvData::PVTimeStamp pvTimeStamp; + epics::pvData::Alarm alarm; + epics::pvData::TimeStamp timeStamp; +}; + + +}} + +#endif /* POWERSUPPLY_H */ diff --git a/examplePowerSupply/src/powerSupplyInclude.dbd b/examplePowerSupply/src/powerSupplyInclude.dbd new file mode 100644 index 0000000..1444fc1 --- /dev/null +++ b/examplePowerSupply/src/powerSupplyInclude.dbd @@ -0,0 +1 @@ +registrar("powerSupplyRegister") diff --git a/examplePowerSupply/src/powerSupplyMain.cpp b/examplePowerSupply/src/powerSupplyMain.cpp new file mode 100644 index 0000000..c7de4c0 --- /dev/null +++ b/examplePowerSupply/src/powerSupplyMain.cpp @@ -0,0 +1,68 @@ +/*powerSupplyMain.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pvDatabase; + + +int main(int argc,char *argv[]) +{ + PVDatabasePtr master = PVDatabase::getMaster(); + ChannelProviderLocalPtr channelProvider = getChannelProviderLocal(); + PVRecordPtr pvRecord; + bool result(false); + String recordName; + recordName = "powerSupply"; + PVStructurePtr pv = createPowerSupply(); + pvRecord = PowerSupply::create(recordName,pv); + result = master->addRecord(pvRecord); + cout << "result of addRecord " << recordName << " " << result << endl; + recordName = "traceRecordPGRPC"; + pvRecord = TraceRecord::create(recordName); + result = master->addRecord(pvRecord); + if(!result) cout<< "record " << recordName << " not added" << endl; + pvRecord.reset(); + ServerContext::shared_pointer pvaServer = + startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true); + cout << "powerSupply\n"; + string str; + while(true) { + cout << "Type exit to stop: \n"; + getline(cin,str); + if(str.compare("exit")==0) break; + + } + pvaServer->shutdown(); + epicsThreadSleep(1.0); + pvaServer->destroy(); + channelProvider->destroy(); + return 0; +} + diff --git a/examplePowerSupply/src/powerSupplyRegister.cpp b/examplePowerSupply/src/powerSupplyRegister.cpp new file mode 100644 index 0000000..963f41b --- /dev/null +++ b/examplePowerSupply/src/powerSupplyRegister.cpp @@ -0,0 +1,69 @@ +/*powerSupplyRegister.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2013.07.24 + */ + + +/* Author: Marty Kraimer */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pvDatabase; +using std::cout; +using std::endl; + + +static const iocshArg testArg0 = { "recordName", iocshArgString }; +static const iocshArg *testArgs[] = { + &testArg0}; + +static const iocshFuncDef powerSupplyFuncDef = { + "powerSupplyCreateRecord", 1, testArgs}; +static void powerSupplyCallFunc(const iocshArgBuf *args) +{ + char *recordName = args[0].sval; + PVStructurePtr pv = createPowerSupply(); + + PowerSupplyPtr record = PowerSupply::create(recordName,pv); + bool result = PVDatabase::getMaster()->addRecord(record); + if(!result) cout << "recordname" << " not added" << endl; +} + +static void powerSupplyRegister(void) +{ + static int firstTime = 1; + if (firstTime) { + firstTime = 0; + iocshRegister(&powerSupplyFuncDef, powerSupplyCallFunc); + } +} +epicsExportRegistrar(powerSupplyRegister); diff --git a/exampleServer/configure/ExampleRELEASE.local b/exampleServer/configure/ExampleRELEASE.local new file mode 100644 index 0000000..95e3783 --- /dev/null +++ b/exampleServer/configure/ExampleRELEASE.local @@ -0,0 +1,8 @@ +EPICS_BASE=/home/install/epics/base +TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top +EPICSV4HOME=/home/hg +PVCOMMON=${EPICSV4HOME}/pvCommonCPP +PVDATA=${EPICSV4HOME}/pvDataCPP +PVACCESS=${EPICSV4HOME}/pvAccessCPP +PVDATABASE=${EPICSV4HOME}/pvDatabaseCPP +PVASRV=${EPICSV4HOME}/pvaSrv diff --git a/exampleServer/example/src/Makefile b/exampleServer/example/src/Makefile index 6595bbb..83f50e7 100644 --- a/exampleServer/example/src/Makefile +++ b/exampleServer/example/src/Makefile @@ -29,7 +29,7 @@ exampleServer_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary exampleServer_LIBS += pvData pvAccess exampleServer_LIBS += pvDatabase exampleServer_LIBS += pvaSrv -exampleServer_LIBS += exampleServerSupport +exampleServer_LIBS += exampleServer exampleServer_LIBS += $(EPICS_BASE_IOC_LIBS) #=========================== diff --git a/exampleServer/iocBoot/exampleServer/st.cmd b/exampleServer/iocBoot/exampleServer/st.cmd index 8528e92..46b8c68 100644 --- a/exampleServer/iocBoot/exampleServer/st.cmd +++ b/exampleServer/iocBoot/exampleServer/st.cmd @@ -17,7 +17,7 @@ cd ${TOP}/iocBoot/${IOC} iocInit() dbl epicsThreadSleep(1.0) -exampleServerCreateRecord pvaServer +exampleServerCreateRecord exampleServer startPVAServer pvdbl diff --git a/exampleServer/src/Makefile b/exampleServer/src/Makefile index aa91808..92b6566 100644 --- a/exampleServer/src/Makefile +++ b/exampleServer/src/Makefile @@ -9,17 +9,26 @@ include $(TOP)/configure/CONFIG # Build an IOC support library # + +PROD_HOST += exampleServerMain +exampleServerMain_SRCS += exampleServerMain.cpp +exampleServerMain_LIBS += Com +exampleServerMain_LIBS += pvData +exampleServerMain_LIBS += pvAccess +exampleServerMain_LIBS += pvDatabase +exampleServerMain_LIBS += exampleServer + DBD += exampleServer.dbd INC += exampleServer.h -LIBRARY_IOC += exampleServerSupport -exampleServerSupport_SRCS += exampleServer.cpp -exampleServerSupport_SRCS += exampleServerRegister.cpp -exampleServerSupport_LIBS += pvData -exampleServerSupport_LIBS += pvAccess -exampleServerSupport_LIBS += pvDatabase -exampleServerSupport_LIBS += $(EPICS_BASE_IOC_LIBS) +LIBRARY_IOC += exampleServer +exampleServer_SRCS += exampleServer.cpp +exampleServer_SRCS += exampleServerRegister.cpp +exampleServer_LIBS += pvData +exampleServer_LIBS += pvAccess +exampleServer_LIBS += pvDatabase +exampleServer_LIBS += $(EPICS_BASE_IOC_LIBS) #=========================== diff --git a/exampleServer/src/exampleServerMain.cpp b/exampleServer/src/exampleServerMain.cpp new file mode 100644 index 0000000..bfe2214 --- /dev/null +++ b/exampleServer/src/exampleServerMain.cpp @@ -0,0 +1,67 @@ +/*ExampleServerMain.cpp */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + */ + +/* Author: Marty Kraimer */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; +using std::tr1::static_pointer_cast; +using namespace epics::pvData; +using namespace epics::pvAccess; +using namespace epics::pvDatabase; +using namespace epics::exampleServer; + +int main(int argc,char *argv[]) +{ + PVDatabasePtr master = PVDatabase::getMaster(); + ChannelProviderLocalPtr channelProvider = getChannelProviderLocal(); + PVRecordPtr pvRecord; + bool result(false); + String recordName; + recordName = "exampleServer"; + pvRecord = ExampleServer::create(recordName); + result = master->addRecord(pvRecord); + cout << "result of addRecord " << recordName << " " << result << endl; + recordName = "traceRecordPGRPC"; + pvRecord = TraceRecord::create(recordName); + result = master->addRecord(pvRecord); + if(!result) cout<< "record " << recordName << " not added" << endl; + pvRecord.reset(); + ServerContext::shared_pointer pvaServer = + startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true); + cout << "exampleServer\n"; + string str; + while(true) { + cout << "Type exit to stop: \n"; + getline(cin,str); + if(str.compare("exit")==0) break; + + } + pvaServer->shutdown(); + epicsThreadSleep(1.0); + pvaServer->destroy(); + channelProvider->destroy(); + return 0; +} + diff --git a/src/Makefile b/src/Makefile index 3975b2c..21b7854 100644 --- a/src/Makefile +++ b/src/Makefile @@ -33,7 +33,6 @@ LIBSRCS += PVAClientRegister.cpp SRC_DIRS += $(DATABASE)/special INC += recordList.h INC += traceRecord.h -INC += powerSupplyRecordTest.h LIBSRCS += recordList.cpp LIBSRCS += traceRecord.cpp diff --git a/src/special/recordList.cpp b/src/special/recordList.cpp index e842046..d6d933e 100644 --- a/src/special/recordList.cpp +++ b/src/special/recordList.cpp @@ -36,7 +36,7 @@ RecordListRecordPtr RecordListRecord::create( resFields[1] = fieldCreate->createScalarArray(pvString); StringArray topNames(2); FieldConstPtrArray topFields(2); - topNames[0] = "arguments"; + topNames[0] = "argument"; topFields[0] = fieldCreate->createStructure(argNames,argFields); topNames[1] = "result"; topFields[1] = fieldCreate->createStructure(resNames,resFields); @@ -69,10 +69,10 @@ bool RecordListRecord::init() { initPVRecord(); PVStructurePtr pvStructure = getPVStructure(); - database = pvStructure->getStringField("arguments.database"); + database = pvStructure->getStringField("argument.database"); if(database.get()==NULL) return false; regularExpression = pvStructure->getStringField( - "arguments.regularExpression"); + "argument.regularExpression"); if(regularExpression.get()==NULL) return false; status = pvStructure->getStringField("result.status"); if(status.get()==NULL) return false; diff --git a/src/special/traceRecord.cpp b/src/special/traceRecord.cpp index f5be33f..bffef40 100644 --- a/src/special/traceRecord.cpp +++ b/src/special/traceRecord.cpp @@ -25,7 +25,7 @@ TraceRecordPtr TraceRecord::create( PVDataCreatePtr pvDataCreate = getPVDataCreate(); StringArray topNames(2); FieldConstPtrArray topFields(2); - topNames[0] = "arguments"; + topNames[0] = "argument"; topNames[1] = "result"; StringArray argNames(2); FieldConstPtrArray argFields(2); @@ -70,9 +70,9 @@ bool TraceRecord::init() { initPVRecord(); PVStructurePtr pvStructure = getPVStructure(); - pvRecordName = pvStructure->getStringField("arguments.recordName"); + pvRecordName = pvStructure->getStringField("argument.recordName"); if(pvRecordName==NULL) return false; - pvLevel = pvStructure->getIntField("arguments.level"); + pvLevel = pvStructure->getIntField("argument.level"); if(pvLevel==NULL) return false; pvResult = pvStructure->getStringField("result.status"); if(pvResult==NULL) return false; diff --git a/test/src/Makefile b/test/src/Makefile index 1fd35d5..dfee24e 100644 --- a/test/src/Makefile +++ b/test/src/Makefile @@ -3,14 +3,17 @@ TOP=.. include $(TOP)/configure/CONFIG PROD_HOST += testPVCopy +testPVCopy_SRCS += powerSupply.cpp testPVCopy_SRCS += testPVCopy.cpp testPVCopy_LIBS += pvDatabase pvAccess pvData Com PROD_HOST += testPVRecord +testPVRecord_SRCS += powerSupply.cpp testPVRecord_SRCS += testPVRecord.cpp testPVRecord_LIBS += pvDatabase pvAccess pvData Com PROD_HOST += testExampleRecord +testExampleRecord_SRCS += powerSupply.cpp testExampleRecord_SRCS += testExampleRecord.cpp testExampleRecord_LIBS += pvDatabase pvAccess pvData Com diff --git a/src/special/powerSupplyRecordTest.h b/test/src/powerSupply.cpp similarity index 55% rename from src/special/powerSupplyRecordTest.h rename to test/src/powerSupply.cpp index 7f72407..af3aab4 100644 --- a/src/special/powerSupplyRecordTest.h +++ b/test/src/powerSupply.cpp @@ -1,4 +1,4 @@ -/* powerSupplyRecordTest.h */ +/* powerSupply.cpp */ /** * Copyright - See the COPYRIGHT that is included with this distribution. * EPICS pvData is distributed subject to a Software License Agreement found @@ -8,80 +8,74 @@ * @author mrk * @date 2013.04.02 */ -#ifndef POWERSUPPLYRECORDTEST_H -#define POWERSUPPLYRECORDTEST_H -#include -#include -#include -#include -#include +#include "powerSupply.h" +#include +#include namespace epics { namespace pvDatabase { +using namespace epics::pvData; - -class PowerSupplyRecordTest; -typedef std::tr1::shared_ptr PowerSupplyRecordTestPtr; - -class PowerSupplyRecordTest : - public PVRecord +PVStructurePtr createPowerSupply() { -public: - POINTER_DEFINITIONS(PowerSupplyRecordTest); - static PowerSupplyRecordTestPtr create( - epics::pvData::String const & recordName, - epics::pvData::PVStructurePtr const & pvStructure); - virtual ~PowerSupplyRecordTest(); - virtual void destroy(); - virtual bool init(); - virtual void process(); - void put(double power,double voltage); - double getPower(); - double getVoltage(); - double getCurrent(); -private: - PowerSupplyRecordTest(epics::pvData::String const & recordName, - epics::pvData::PVStructurePtr const & pvStructure); - epics::pvData::PVDoublePtr pvCurrent; - epics::pvData::PVDoublePtr pvPower; - epics::pvData::PVDoublePtr pvVoltage; - epics::pvData::PVAlarm pvAlarm; - epics::pvData::PVTimeStamp pvTimeStamp; - epics::pvData::Alarm alarm; - epics::pvData::TimeStamp timeStamp; -}; + FieldCreatePtr fieldCreate = getFieldCreate(); + StandardFieldPtr standardField = getStandardField(); + PVDataCreatePtr pvDataCreate = getPVDataCreate(); -PowerSupplyRecordTestPtr PowerSupplyRecordTest::create( - epics::pvData::String const & recordName, - epics::pvData::PVStructurePtr const & pvStructure) + size_t nfields = 5; + StringArray names; + names.reserve(nfields); + FieldConstPtrArray powerSupply; + powerSupply.reserve(nfields); + names.push_back("alarm"); + powerSupply.push_back(standardField->alarm()); + names.push_back("timeStamp"); + powerSupply.push_back(standardField->timeStamp()); + String properties("alarm,display"); + names.push_back("voltage"); + powerSupply.push_back(standardField->scalar(pvDouble,properties)); + names.push_back("power"); + powerSupply.push_back(standardField->scalar(pvDouble,properties)); + names.push_back("current"); + powerSupply.push_back(standardField->scalar(pvDouble,properties)); + return pvDataCreate->createPVStructure( + fieldCreate->createStructure(names,powerSupply)); +} + +using namespace epics::pvData; + + +PowerSupplyPtr PowerSupply::create( + String const & recordName, + PVStructurePtr const & pvStructure) { - PowerSupplyRecordTestPtr pvRecord( - new PowerSupplyRecordTest(recordName,pvStructure)); + PowerSupplyPtr pvRecord( + new PowerSupply(recordName,pvStructure)); if(!pvRecord->init()) pvRecord.reset(); return pvRecord; } -PowerSupplyRecordTest::PowerSupplyRecordTest( - epics::pvData::String const & recordName, - epics::pvData::PVStructurePtr const & pvStructure) +PowerSupply::PowerSupply( + String const & recordName, + PVStructurePtr const & pvStructure) : PVRecord(recordName,pvStructure) { } -PowerSupplyRecordTest::~PowerSupplyRecordTest() +PowerSupply::~PowerSupply() { } -void PowerSupplyRecordTest::destroy() +void PowerSupply::destroy() { PVRecord::destroy(); } -bool PowerSupplyRecordTest::init() +bool PowerSupply::init() { initPVRecord(); - epics::pvData::PVStructurePtr pvStructure = getPVStructure(); - epics::pvData::PVFieldPtr pvField; + PVStructurePtr pvStructure = getPVStructure(); + PVFieldPtr pvField; bool result; pvField = pvStructure->getSubField("timeStamp"); if(pvField.get()==NULL) { @@ -103,7 +97,7 @@ bool PowerSupplyRecordTest::init() std::cerr << "no alarm" << std::endl; return false; } - epics::pvData::String name; + String name; name = "current.value"; pvField = pvStructure->getSubField(name); if(pvField.get()==NULL) { @@ -143,7 +137,7 @@ bool PowerSupplyRecordTest::init() return true; } -void PowerSupplyRecordTest::process() +void PowerSupply::process() { timeStamp.getCurrent(); pvTimeStamp.set(timeStamp); @@ -151,39 +145,37 @@ void PowerSupplyRecordTest::process() double power = pvPower->get(); if(voltage<1e-3 && voltage>-1e-3) { alarm.setMessage("bad voltage"); - alarm.setSeverity(epics::pvData::majorAlarm); + alarm.setSeverity(majorAlarm); pvAlarm.set(alarm); return; } double current = power/voltage; pvCurrent->put(current); alarm.setMessage(""); - alarm.setSeverity(epics::pvData::noAlarm); + alarm.setSeverity(noAlarm); pvAlarm.set(alarm); } -void PowerSupplyRecordTest::put(double power,double voltage) +void PowerSupply::put(double power,double voltage) { pvPower->put(power); pvVoltage->put(voltage); } -double PowerSupplyRecordTest::getPower() +double PowerSupply::getPower() { return pvPower->get(); } -double PowerSupplyRecordTest::getVoltage() +double PowerSupply::getVoltage() { return pvVoltage->get(); } -double PowerSupplyRecordTest::getCurrent() +double PowerSupply::getCurrent() { return pvCurrent->get(); } }} - -#endif /* POWERSUPPLYRECORDTEST_H */ diff --git a/test/src/powerSupply.h b/test/src/powerSupply.h new file mode 100644 index 0000000..fb98c49 --- /dev/null +++ b/test/src/powerSupply.h @@ -0,0 +1,58 @@ +/* powerSupply.h */ +/** + * Copyright - See the COPYRIGHT that is included with this distribution. + * EPICS pvData is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + */ +/** + * @author mrk + * @date 2013.04.02 + */ +#ifndef POWERSUPPLY_H +#define POWERSUPPLY_H + +#include +#include +#include +#include +#include + +namespace epics { namespace pvDatabase { + +extern epics::pvData::PVStructurePtr createPowerSupply(); + +class PowerSupply; +typedef std::tr1::shared_ptr PowerSupplyPtr; + +class PowerSupply : + public PVRecord +{ +public: + POINTER_DEFINITIONS(PowerSupply); + static PowerSupplyPtr create( + epics::pvData::String const & recordName, + epics::pvData::PVStructurePtr const & pvStructure); + virtual ~PowerSupply(); + virtual void destroy(); + virtual bool init(); + virtual void process(); + void put(double power,double voltage); + double getPower(); + double getVoltage(); + double getCurrent(); +private: + PowerSupply(epics::pvData::String const & recordName, + epics::pvData::PVStructurePtr const & pvStructure); + epics::pvData::PVDoublePtr pvCurrent; + epics::pvData::PVDoublePtr pvPower; + epics::pvData::PVDoublePtr pvVoltage; + epics::pvData::PVAlarm pvAlarm; + epics::pvData::PVTimeStamp pvTimeStamp; + epics::pvData::Alarm alarm; + epics::pvData::TimeStamp timeStamp; +}; + + +}} + +#endif /* POWERSUPPLY_H */ diff --git a/test/src/testExampleRecord.cpp b/test/src/testExampleRecord.cpp index 1ee881b..ba21e3b 100644 --- a/test/src/testExampleRecord.cpp +++ b/test/src/testExampleRecord.cpp @@ -29,7 +29,7 @@ #include #include #include -#include +#include "powerSupply.h" using namespace std; using std::tr1::static_pointer_cast; @@ -38,30 +38,6 @@ using namespace epics::pvAccess; using namespace epics::pvDatabase; -static PVStructurePtr createPowerSupply() -{ - FieldCreatePtr fieldCreate = getFieldCreate(); - StandardFieldPtr standardField = getStandardField(); - PVDataCreatePtr pvDataCreate = getPVDataCreate(); - size_t nfields = 5; - StringArray names; - names.reserve(nfields); - FieldConstPtrArray powerSupply; - powerSupply.reserve(nfields); - names.push_back("alarm"); - powerSupply.push_back(standardField->alarm()); - names.push_back("timeStamp"); - powerSupply.push_back(standardField->timeStamp()); - String properties("alarm,display"); - names.push_back("voltage"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - names.push_back("power"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - names.push_back("current"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - return pvDataCreate->createPVStructure( - fieldCreate->createStructure(names,powerSupply)); -} void test() @@ -86,9 +62,9 @@ void test() pvRecord.reset(); recordName = "powerSupplyExample"; pvStructure.reset(); + PowerSupplyPtr psr; pvStructure = createPowerSupply(); - PowerSupplyRecordTestPtr psr = - PowerSupplyRecordTest::create(recordName,pvStructure); + psr = PowerSupply::create("powerSupply",pvStructure); if(psr.get()==NULL) { cout << "PowerSupplyRecordTest::create failed" << endl; return; diff --git a/test/src/testPVCopy.cpp b/test/src/testPVCopy.cpp index 2f36230..3615a03 100644 --- a/test/src/testPVCopy.cpp +++ b/test/src/testPVCopy.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include "powerSupply.h" using namespace std; @@ -73,32 +73,6 @@ static PVRecordPtr createScalarArray( return PVRecord::create(recordName,pvStructure); } -static PowerSupplyRecordTestPtr createPowerSupply(String const & recordName) -{ - FieldCreatePtr fieldCreate = getFieldCreate(); - StandardFieldPtr standardField = getStandardField(); - PVDataCreatePtr pvDataCreate = getPVDataCreate(); - size_t nfields = 5; - StringArray names; - names.reserve(nfields); - FieldConstPtrArray powerSupply; - powerSupply.reserve(nfields); - names.push_back("alarm"); - powerSupply.push_back(standardField->alarm()); - names.push_back("timeStamp"); - powerSupply.push_back(standardField->timeStamp()); - String properties("alarm,display"); - names.push_back("voltage"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - names.push_back("power"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - names.push_back("current"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - return PowerSupplyRecordTest::create(recordName, - pvDataCreate->createPVStructure( - fieldCreate->createStructure(names,powerSupply))); -} - static void testPVScalar( String const & valueNameRecord, String const & valueNameCopy, @@ -370,7 +344,7 @@ static void powerSupplyTest() { cout << endl << endl << "****powerSupplyTest****" << endl; RequesterPtr requester(new MyRequester("exampleTest")); - PowerSupplyRecordTestPtr pvRecord; + PowerSupplyPtr pvRecord; String request; PVStructurePtr pvRequest; PVRecordFieldPtr pvRecordField; @@ -380,7 +354,8 @@ static void powerSupplyTest() String valueNameCopy; CreateRequest::shared_pointer createRequest = CreateRequest::create(); - pvRecord = createPowerSupply("powerSupply"); + PVStructurePtr pv = createPowerSupply(); + pvRecord = PowerSupply::create("powerSupply",pv); valueNameRecord = request = "power.value"; pvRequest = createRequest->createRequest(request); builder.clear(); pvRequest->toString(&builder); diff --git a/test/src/testPVRecord.cpp b/test/src/testPVRecord.cpp index e35243d..ecfc388 100644 --- a/test/src/testPVRecord.cpp +++ b/test/src/testPVRecord.cpp @@ -26,15 +26,13 @@ #include #include #include -#include #include -#include +#include "powerSupply.h" using namespace std; using std::tr1::static_pointer_cast; using namespace epics::pvData; -using namespace epics::pvAccess; using namespace epics::pvDatabase; static PVRecordPtr createScalar( @@ -57,32 +55,6 @@ static PVRecordPtr createScalarArray( return PVRecord::create(recordName,pvStructure); } -static PowerSupplyRecordTestPtr createPowerSupply(String const & recordName) -{ - FieldCreatePtr fieldCreate = getFieldCreate(); - StandardFieldPtr standardField = getStandardField(); - PVDataCreatePtr pvDataCreate = getPVDataCreate(); - size_t nfields = 5; - StringArray names; - names.reserve(nfields); - FieldConstPtrArray powerSupply; - powerSupply.reserve(nfields); - names.push_back("alarm"); - powerSupply.push_back(standardField->alarm()); - names.push_back("timeStamp"); - powerSupply.push_back(standardField->timeStamp()); - String properties("alarm,display"); - names.push_back("voltage"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - names.push_back("power"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - names.push_back("current"); - powerSupply.push_back(standardField->scalar(pvDouble,properties)); - return PowerSupplyRecordTest::create(recordName, - pvDataCreate->createPVStructure( - fieldCreate->createStructure(names,powerSupply))); -} - static void scalarTest() { cout << endl << endl << "****scalarTest****" << endl; @@ -102,8 +74,9 @@ static void arrayTest() static void powerSupplyTest() { cout << endl << endl << "****powerSupplyTest****" << endl; - PowerSupplyRecordTestPtr pvRecord; - pvRecord = createPowerSupply("powerSupply"); + PVRecordPtr pvRecord; + PVStructurePtr pv = createPowerSupply(); + pvRecord = PowerSupply::create("powerSupply",pv); pvRecord->destroy(); }