interim commit. First working version of record.

This commit is contained in:
Marty Kraimer
2012-12-07 07:00:13 -05:00
parent fcb9e76e01
commit 179d45e264
10 changed files with 968 additions and 30 deletions

View File

@ -6,8 +6,8 @@ DIRS += configure
DIRS += src DIRS += src
src_DEPEND_DIRS = configure src_DEPEND_DIRS = configure
#DIRS += test DIRS += test
#test_DEPEND_DIRS = src test_DEPEND_DIRS = src
DIRS += example DIRS += example
example_DEPEND_DIRS = src example_DEPEND_DIRS = src

View File

@ -38,6 +38,7 @@ PVRecordPtr ExampleRecord::create(String const & recordName)
PVStructurePtr pvStructure = getStandardPVField()->scalar(pvLong,properties); PVStructurePtr pvStructure = getStandardPVField()->scalar(pvLong,properties);
PVLongPtr pvValue = pvStructure->getLongField("value"); PVLongPtr pvValue = pvStructure->getLongField("value");
PVRecordPtr pvRecord(new ExampleRecord(recordName,pvStructure,pvValue)); PVRecordPtr pvRecord(new ExampleRecord(recordName,pvStructure,pvValue));
pvRecord->init();
return pvRecord; return pvRecord;
} }
ExampleRecord::ExampleRecord( ExampleRecord::ExampleRecord(
@ -51,11 +52,14 @@ PVRecordPtr ExampleRecord::create(String const & recordName)
bool ExampleRecord::isSynchronous() {return true;} bool ExampleRecord::isSynchronous() {return true;}
void ExampleRecord::process( void ExampleRecord::process(
RecordProcessRequesterPtr const &processRequester) RecordProcessRequesterPtr const &processRequester,bool alreadyLocked)
{ {
if(!alreadyLocked) lock();
pvValue->put(pvValue->get() + 1); pvValue->put(pvValue->get() + 1);
processRequester->recordProcessResult(Status::Ok); processRequester->recordProcessResult(Status::Ok);
unlock();
processRequester->recordProcessComplete(); processRequester->recordProcessComplete();
dequeueProcessRequest(processRequester);
} }

View File

@ -29,7 +29,8 @@ public:
virtual ~ExampleRecord(); virtual ~ExampleRecord();
virtual bool isSynchronous(); virtual bool isSynchronous();
virtual void process( virtual void process(
epics::pvDatabase::RecordProcessRequesterPtr const &processRequester); epics::pvDatabase::RecordProcessRequesterPtr const &processRequester,
bool alreadyLocked);
private: private:
ExampleRecord(epics::pvData::String const & recordName, ExampleRecord(epics::pvData::String const & recordName,
epics::pvData::PVStructurePtr const & pvStructure, epics::pvData::PVStructurePtr const & pvStructure,

View File

@ -21,10 +21,454 @@ PVRecord::PVRecord(
String const & recordName, String const & recordName,
PVStructurePtr const & pvStructure) PVStructurePtr const & pvStructure)
: recordName(recordName), : recordName(recordName),
pvStructure(pvStructure) pvStructure(pvStructure),
{} convert(getConvert()),
thelock(mutex),
depthGroupPut(0)
{
thelock.unlock();
}
void PVRecord::init()
{
PVRecordStructurePtr parent;
pvRecordStructure = PVRecordStructurePtr(
new PVRecordStructure(pvStructure,parent,getPtrSelf()));
pvRecordStructure->init();
pvStructure->setRequester(getPtrSelf());
}
PVRecord::~PVRecord() {} PVRecord::~PVRecord() {}
}} String PVRecord::getRecordName() {return recordName;}
PVRecordStructurePtr PVRecord::getPVRecordStructure() {return pvRecordStructure;}
PVRecordFieldPtr PVRecord::findPVRecordField(PVFieldPtr const & pvField)
{
return findPVRecordField(pvRecordStructure,pvField);
}
PVRecordFieldPtr PVRecord::findPVRecordField(
PVRecordStructurePtr const & pvrs,
PVFieldPtr const & pvField)
{
size_t desiredOffset = pvField->getFieldOffset();
PVFieldPtr pvf = pvrs->getPVField();
size_t offset = pvf->getFieldOffset();
if(offset==desiredOffset) return pvrs;
PVRecordFieldPtrArrayPtr pvrfpap = pvrs->getPVRecordFields();
PVRecordFieldPtrArray::iterator iter;
for (iter = pvrfpap.get()->begin(); iter!=pvrfpap.get()->end(); iter++ ) {
PVRecordFieldPtr pvrf = *iter;
pvf = pvrf->getPVField();
offset = pvf->getFieldOffset();
if(offset==desiredOffset) return pvrf;
size_t nextOffset = pvf->getNextFieldOffset();
if(nextOffset<=desiredOffset) continue;
return findPVRecordField(
static_pointer_cast<PVRecordStructure>(pvrf),
pvField);
}
throw std::logic_error(
recordName + " pvField "
+ pvField->getFieldName() + " not in PVRecord");
}
void PVRecord::lock() {thelock.lock();}
void PVRecord::unlock() {thelock.unlock();}
bool PVRecord::tryLock() {return thelock.tryLock();}
bool PVRecord::addPVRecordClient(PVRecordClientPtr const & pvRecordClient)
{
lock();
std::list<PVRecordClientPtr>::iterator iter;
for (iter = pvRecordClientList.begin();
iter!=pvRecordClientList.end();
iter++ )
{
if((*iter).get()==pvRecordClient.get()) {
unlock();
return false;
}
}
pvRecordClientList.push_back(pvRecordClient);
unlock();
return true;
}
bool PVRecord::removePVRecordClient(PVRecordClientPtr const & pvRecordClient)
{
lock();
std::list<PVRecordClientPtr>::iterator iter;
for (iter = pvRecordClientList.begin();
iter!=pvRecordClientList.end();
iter++ )
{
if((*iter).get()==pvRecordClient.get()) {
pvRecordClientList.erase(iter);
unlock();
return true;
}
}
unlock();
return false;
}
void PVRecord::detachClients()
{
lock();
std::list<PVRecordClientPtr>::iterator iter;
for (iter = pvRecordClientList.begin();
iter!=pvRecordClientList.end();
iter++ )
{
(*iter)->detach(getPtrSelf());
}
pvRecordClientList.clear();
unlock();
}
void PVRecord::beginGroupPut()
{
if(++depthGroupPut>1) return;
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++)
{
(*iter).get()->beginGroupPut(getPtrSelf());
}
}
void PVRecord::endGroupPut()
{
if(--depthGroupPut>0) return;
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++)
{
(*iter).get()->endGroupPut(getPtrSelf());
}
}
bool PVRecord::addListener(PVListenerPtr const & pvListener)
{
lock();
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ )
{
if((*iter).get()==pvListener.get()) {
unlock();
return false;
}
}
pvListenerList.push_back(pvListener);
unlock();
return true;
}
bool PVRecord::removeListener(PVListenerPtr const & pvListener)
{
lock();
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ )
{
if((*iter).get()==pvListener.get()) {
pvListenerList.erase(iter);
unlock();
return true;
}
}
unlock();
return false;
}
void PVRecord::queueProcessRequest(
RecordProcessRequesterPtr const &recordProcessRequester)
{
bool isFirst = false;
lock();
processRequesterQueue.push_back(recordProcessRequester);
if(processRequesterQueue.size()==1) isFirst = true;
unlock();
if(isFirst) recordProcessRequester->becomeProcessor();
}
void PVRecord::dequeueProcessRequest(
RecordProcessRequesterPtr const &recordProcessRequester)
{
RecordProcessRequesterPtr next;
lock();
RecordProcessRequesterPtr processRequester =
processRequesterQueue[0];
if(processRequester.get()!=recordProcessRequester.get()) {
message(
"PVRecord::dequeueProcessRequest illegal requester",
errorMessage);
return;
}
processRequesterQueue.pop_front();
if(processRequesterQueue.size()>0) next = processRequesterQueue[0];
unlock();
if(next.get()!=NULL) next->becomeProcessor();
}
bool PVRecord::addRequester(epics::pvData::RequesterPtr const & requester)
{
lock();
std::list<RequesterPtr>::iterator iter;
for (iter = requesterList.begin(); iter!=requesterList.end(); iter++ ) {
if((*iter).get()==requester.get()) {
unlock();
return false;
}
}
requesterList.push_back(requester);
unlock();
return true;
}
bool PVRecord::removeRequester(epics::pvData::RequesterPtr const & requester)
{
lock();
std::list<RequesterPtr>::iterator iter;
for (iter = requesterList.begin(); iter!=requesterList.end(); iter++ ) {
if((*iter).get()==requester.get()) {
requesterList.erase(iter);
unlock();
return true;
}
}
unlock();
return false;
}
void PVRecord::message(String const & message,MessageType messageType)
{
if(requesterList.size()==0 ) {
String xxx(getMessageTypeName(messageType) + " " + message);
printf("%s\n",xxx.c_str());
return;
}
std::list<epics::pvData::RequesterPtr>::iterator iter;
for(iter = requesterList.begin(); iter != requesterList.end(); ++iter) {
(*iter)->message(message,messageType);
}
}
void PVRecord::message(
PVRecordFieldPtr const & pvRecordField,
String const & message,
MessageType messageType)
{
this->message(pvRecordField->getFullName() + " " + message,messageType);
}
void PVRecord::toString(StringBuilder buf)
{
toString(buf,0);
}
void PVRecord::toString(StringBuilder buf,int indentLevel)
{
*buf += "\nrecord " + recordName + " ";
pvRecordStructure->getPVStructure()->toString(buf, indentLevel);
}
PVRecordField::PVRecordField(
PVFieldPtr const & pvField,
PVRecordStructurePtr const &parent,
PVRecordPtr const & pvRecord)
: pvField(pvField),
parent(parent),
pvRecord(pvRecord)
{
}
void PVRecordField::init()
{
fullFieldName = pvField->getFieldName();
PVRecordStructurePtr pvParent = parent;
while(pvParent.get()!= NULL) {
String parentName = pvParent->getPVField()->getFieldName();
if(parentName.size()>0) {
fullFieldName = pvParent->getPVField()->getFieldName()
+ '.' + fullFieldName;
}
pvParent = pvParent->getParent();
}
if(fullFieldName.size()>0) {
fullName = pvRecord->getRecordName() + '.' + fullFieldName;
} else {
fullName = pvRecord->getRecordName();
}
pvField->setPostHandler(getPtrSelf());
}
PVRecordField::~PVRecordField() {}
PVRecordStructurePtr PVRecordField::getParent() {return parent;}
PVFieldPtr PVRecordField::getPVField() {return pvField;}
String PVRecordField::getFullFieldName() {return fullFieldName; }
String PVRecordField::getFullName() {return fullName; }
PVRecordPtr PVRecordField::getPVRecord() {return pvRecord;}
bool PVRecordField::addListener(PVListenerPtr const & pvListener)
{
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ ) {
if((*iter).get()==pvListener.get()) {
return false;
}
}
pvListenerList.push_back(pvListener);
return true;
}
void PVRecordField::removeListener(PVListenerPtr const & pvListener)
{
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ ) {
if((*iter).get()==pvListener.get()) {
pvListenerList.erase(iter);
return;
}
}
}
void PVRecordField::postPut()
{
callListener();
std::list<PVListenerPtr>::iterator iter;
PVRecordStructurePtr pvParent = getParent();
while(pvParent.get()!=NULL) {
std::list<PVListenerPtr> list = pvParent->pvListenerList;
for (iter = list.begin(); iter!=list.end(); iter++ ) {
(*iter)->dataPut(pvParent,getPtrSelf());
}
pvParent = pvParent->getParent();
}
}
void PVRecordField::message(String const & message,MessageType messageType)
{
pvRecord->message(getPtrSelf(),message,messageType);
}
void PVRecordField::callListener()
{
std::list<PVListenerPtr>::iterator iter;
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ ) {
(*iter)->dataPut(getPtrSelf());
}
}
PVRecordStructure::PVRecordStructure(
PVStructurePtr const &pvStructure,
PVRecordStructurePtr const &parent,
PVRecordPtr const & pvRecord)
:
PVRecordField(pvStructure,parent,pvRecord),
pvStructure(pvStructure),
pvRecordFields(new PVRecordFieldPtrArray)
{
}
PVRecordStructure::~PVRecordStructure() {}
void PVRecordStructure::init()
{
PVRecordField::init();
const PVFieldPtrArray & pvFields = pvStructure->getPVFields();
size_t numFields = pvFields.size();
pvRecordFields->reserve( numFields);
PVRecordStructurePtr self =
static_pointer_cast<PVRecordStructure>(getPtrSelf());
PVRecordPtr pvRecord = getPVRecord();
for(size_t i=0; i<numFields; i++) {
PVFieldPtr pvField = pvFields[i];
if(pvField->getField()->getType()==structure) {
PVStructurePtr xxx = static_pointer_cast<PVStructure>(pvField);
PVRecordStructurePtr pvRecordStructure(
new PVRecordStructure(xxx,self,pvRecord));
pvRecordFields->push_back(pvRecordStructure);
pvRecordStructure->init();
} else {
PVRecordFieldPtr pvRecordField(
new PVRecordField(pvField,self,pvRecord));
pvRecordFields->push_back(pvRecordField);
pvRecordField->init();
}
}
}
PVRecordFieldPtrArrayPtr PVRecordStructure::getPVRecordFields()
{
return pvRecordFields;
}
PVStructurePtr PVRecordStructure::getPVStructure() {return pvStructure;}
void PVRecordStructure::removeListener(PVListenerPtr const & pvListener)
{
PVRecordField::removeListener(pvListener);
size_t numFields = pvRecordFields->size();
for(size_t i=0; i<numFields; i++) {
PVRecordFieldPtr pvRecordField = (*pvRecordFields.get())[i];
pvRecordField->removeListener(pvListener);
}
}
void PVRecordStructure::postPut()
{
PVRecordField::postPut();
size_t numFields = pvRecordFields->size();
for(size_t i=0; i<numFields; i++) {
PVRecordFieldPtr pvRecordField = (*pvRecordFields.get())[i];
pvRecordField->callListener();
}
}
PVDatabase::PVDatabase()
{
}
PVDatabase::~PVDatabase() {}
PVDatabasePtr PVDatabase::getMaster()
{
PVDatabasePtr xxx;
return xxx;
}
PVRecordPtr PVDatabase::findRecord(String const& recordName)
{
PVRecordPtr xxx;
return xxx;
}
bool PVDatabase::addRecord(PVRecordPtr const & record)
{
return false;
}
bool PVDatabase::removeRecord(PVRecordPtr const & record)
{
return false;
}
String PVDatabase::getRequesterName()
{
String xxx;
return xxx;
}
void PVDatabase::message(String const & message,MessageType messageType)
{
}
}}

View File

@ -11,7 +11,11 @@
#ifndef PVDATABASE_H #ifndef PVDATABASE_H
#define PVDATABASE_H #define PVDATABASE_H
#include <list>
#include <deque>
#include <pv/pvAccess.h> #include <pv/pvAccess.h>
#include <pv/convert.h>
namespace epics { namespace pvDatabase { namespace epics { namespace pvDatabase {
@ -39,7 +43,9 @@ class PVDatabase;
typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr; typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
class PVRecord class PVRecord :
public epics::pvData::Requester,
public std::tr1::enable_shared_from_this<PVRecord>
{ {
public: public:
POINTER_DEFINITIONS(PVRecord); POINTER_DEFINITIONS(PVRecord);
@ -48,7 +54,8 @@ public:
epics::pvData::PVStructurePtr const & pvStructure); epics::pvData::PVStructurePtr const & pvStructure);
virtual ~PVRecord(); virtual ~PVRecord();
virtual void process( virtual void process(
RecordProcessRequesterPtr const &recordProcessRequester) = 0; RecordProcessRequesterPtr const &recordProcessRequester,
bool alreadyLocked) = 0;
virtual bool isSynchronous() = 0; virtual bool isSynchronous() = 0;
epics::pvData::String getRecordName(); epics::pvData::String getRecordName();
PVRecordStructurePtr getPVRecordStructure(); PVRecordStructurePtr getPVRecordStructure();
@ -56,34 +63,63 @@ public:
epics::pvData::PVFieldPtr const & pvField); epics::pvData::PVFieldPtr const & pvField);
void lock(); void lock();
void unlock(); void unlock();
void registerClient(PVRecordClientPtr const & pvRecordClient); bool tryLock();
void unregisterClient(PVRecordClientPtr const & pvRecordClient); bool addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
bool removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
void detachClients(); void detachClients();
void beginGroupPut(); void beginGroupPut();
void endGroupPut(); void endGroupPut();
void registerListener(PVListenerPtr const & pvListener); bool addListener(PVListenerPtr const & pvListener);
void unregisterListener(PVListenerPtr const & pvListener); bool removeListener(PVListenerPtr const & pvListener);
void removeEveryListener();
epics::pvData::Status processRequest();
void queueProcessRequest( void queueProcessRequest(
RecordProcessRequesterPtr const &recordProcessRequester); RecordProcessRequesterPtr const &recordProcessRequester);
void addRequester(epics::pvData::RequesterPtr const & requester); void dequeueProcessRequest(
void removeRequester(epics::pvData::RequesterPtr const & requester); RecordProcessRequesterPtr const &recordProcessRequester);
void message( bool addRequester(epics::pvData::RequesterPtr const & requester);
bool removeRequester(epics::pvData::RequesterPtr const & requester);
virtual epics::pvData::String getRequesterName() {return getRecordName();}
virtual void message(
epics::pvData::String const & message, epics::pvData::String const & message,
epics::pvData::MessageType messageType); epics::pvData::MessageType messageType);
epics::pvData::String toString(); void message(
epics::pvData::String toString(int indentLevel); PVRecordFieldPtr const & pvRecordField,
epics::pvData::String const & message,
epics::pvData::MessageType messageType);
void toString(epics::pvData::StringBuilder buf);
void toString(epics::pvData::StringBuilder buf,int indentLevel);
//init MUST be called after derived class is constructed
void init();
protected:
PVRecordPtr getPtrSelf()
{
return shared_from_this();
}
private: private:
PVRecordFieldPtr findPVRecordField(
PVRecordStructurePtr const & pvrs,
epics::pvData::PVFieldPtr const & pvField);
epics::pvData::String recordName; epics::pvData::String recordName;
epics::pvData::PVStructurePtr pvStructure; epics::pvData::PVStructurePtr pvStructure;
epics::pvData::ConvertPtr convert;
PVRecordStructurePtr pvRecordStructure;
std::deque<RecordProcessRequesterPtr> processRequesterQueue;
std::list<PVListenerPtr> pvListenerList;
std::list<PVRecordClientPtr> pvRecordClientList;
std::list<epics::pvData::RequesterPtr> requesterList;
epics::pvData::Mutex mutex;
epics::pvData::Lock thelock;
int depthGroupPut;
}; };
class PVRecordField { class PVRecordField :
public virtual epics::pvData::PostHandler,
public std::tr1::enable_shared_from_this<PVRecordField>
{
public: public:
POINTER_DEFINITIONS(PVRecordField); POINTER_DEFINITIONS(PVRecordField);
PVRecordField( PVRecordField(
epics::pvData::PVFieldPtr const & pvField, epics::pvData::PVFieldPtr const & pvField,
PVRecordStructurePtr const &parent,
PVRecordPtr const & pvRecord); PVRecordPtr const & pvRecord);
virtual ~PVRecordField(); virtual ~PVRecordField();
PVRecordStructurePtr getParent(); PVRecordStructurePtr getParent();
@ -92,11 +128,28 @@ public:
epics::pvData::String getFullName(); epics::pvData::String getFullName();
PVRecordPtr getPVRecord(); PVRecordPtr getPVRecord();
bool addListener(PVListenerPtr const & pvListener); bool addListener(PVListenerPtr const & pvListener);
void removeListener(PVListenerPtr const & pvListener); virtual void removeListener(PVListenerPtr const & pvListener);
void postPut(); virtual void postPut();
virtual void message( virtual void message(
epics::pvData::String const & message, epics::pvData::String const & message,
epics::pvData::MessageType messageType); epics::pvData::MessageType messageType);
protected:
PVRecordFieldPtr getPtrSelf()
{
return shared_from_this();
}
virtual void init();
private:
void callListener();
std::list<PVListenerPtr> pvListenerList;
epics::pvData::PVFieldPtr pvField;
PVRecordStructurePtr parent;
PVRecordPtr pvRecord;
epics::pvData::String fullName;
epics::pvData::String fullFieldName;
friend class PVRecordStructure;
friend class PVRecord;
}; };
class PVRecordStructure : public PVRecordField { class PVRecordStructure : public PVRecordField {
@ -104,19 +157,25 @@ public:
POINTER_DEFINITIONS(PVRecordStructure); POINTER_DEFINITIONS(PVRecordStructure);
PVRecordStructure( PVRecordStructure(
epics::pvData::PVStructurePtr const &pvStructure, epics::pvData::PVStructurePtr const &pvStructure,
PVRecordFieldPtrArrayPtr const &pvRecordField); PVRecordStructurePtr const &parent,
PVRecordPtr const & pvRecord);
virtual ~PVRecordStructure(); virtual ~PVRecordStructure();
PVRecordFieldPtrArrayPtr getPVRecordFields(); PVRecordFieldPtrArrayPtr getPVRecordFields();
epics::pvData::PVStructurePtr getPVStructure(); epics::pvData::PVStructurePtr getPVStructure();
virtual void message( virtual void removeListener(PVListenerPtr const & pvListener);
epics::pvData::String const & message, virtual void postPut();
epics::pvData::MessageType messageType); protected:
virtual void init();
private:
epics::pvData::PVStructurePtr pvStructure;
PVRecordFieldPtrArrayPtr pvRecordFields;
friend class PVRecord;
}; };
class PVListener { class PVListener {
public: public:
POINTER_DEFINITIONS(PVListener); POINTER_DEFINITIONS(PVListener);
virtual ~PVListener(); virtual ~PVListener() {}
virtual void dataPut(PVRecordFieldPtr const & pvRecordField) = 0; virtual void dataPut(PVRecordFieldPtr const & pvRecordField) = 0;
virtual void dataPut( virtual void dataPut(
PVRecordStructurePtr const & requested, PVRecordStructurePtr const & requested,
@ -131,15 +190,16 @@ class RecordProcessRequester :
{ {
public: public:
POINTER_DEFINITIONS(RecordProcessRequester); POINTER_DEFINITIONS(RecordProcessRequester);
virtual ~RecordProcessRequester(); virtual ~RecordProcessRequester() {}
virtual void becomeProcessor() = 0; virtual void becomeProcessor() = 0;
virtual void recordProcessResult(epics::pvData::Status status) = 0; virtual void recordProcessResult(epics::pvData::Status status) = 0;
virtual void recordProcessComplete() = 0; virtual void recordProcessComplete() = 0;
}; };
class PVRecordClient { class PVRecordClient {
public:
POINTER_DEFINITIONS(PVRecordClient); POINTER_DEFINITIONS(PVRecordClient);
virtual ~PVRecordClient(); virtual ~PVRecordClient() {}
virtual void detach(PVRecordPtr const & pvRecord) = 0; virtual void detach(PVRecordPtr const & pvRecord) = 0;
}; };
@ -151,6 +211,10 @@ public:
PVRecordPtr findRecord(epics::pvData::String const& recordName); PVRecordPtr findRecord(epics::pvData::String const& recordName);
bool addRecord(PVRecordPtr const & record); bool addRecord(PVRecordPtr const & record);
bool removeRecord(PVRecordPtr const & record); bool removeRecord(PVRecordPtr const & record);
virtual epics::pvData::String getRequesterName();
virtual void message(
epics::pvData::String const & message,
epics::pvData::MessageType messageType);
private: private:
PVDatabase(); PVDatabase();
}; };

5
test/Makefile Normal file
View File

@ -0,0 +1,5 @@
TOP = ..
include $(TOP)/configure/CONFIG
DIRS += record
include $(TOP)/configure/RULES_DIRS

13
test/record/Makefile Normal file
View File

@ -0,0 +1,13 @@
TOP=../..
include $(TOP)/configure/CONFIG
PROD_HOST += testRecord
testRecord_SRCS += testRecord.cpp
testRecord_SRCS += testRecordMain.cpp
testRecord_LIBS += pvDatabase pvAccess pvData Com
include $(TOP)/configure/RULES
#----------------------------------------
# ADD RULES AFTER THIS LINE

View File

@ -0,0 +1,68 @@
/* testRecord.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
*/
/* Marty Kraimer 2011.03 */
/* This connects to a V3 record and presents the data as a PVStructure
* It provides access to value, alarm, display, and control.
*/
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <stdexcept>
#include <memory>
#include <pv/standardPVField.h>
#include "testRecord.h"
namespace epics { namespace pvDatabase {
using namespace epics::pvData;
using namespace epics::pvAccess;
using std::tr1::static_pointer_cast;
TestRecord::~TestRecord(){}
PVRecordPtr TestRecord::create(String const & recordName)
{
String properties("alarm,timeStamp,display,control,valueAlarm");
PVStructurePtr pvStructure = getStandardPVField()->scalar(pvLong,properties);
PVLongPtr pvValue = pvStructure->getLongField("value");
PVRecordPtr pvRecord(new TestRecord(recordName,pvStructure,pvValue));
pvRecord->init();
return pvRecord;
}
TestRecord::TestRecord(
String const & recordName,
PVStructurePtr const & pvStructure,
PVLongPtr const &pvValue)
: PVRecord(recordName,pvStructure),
pvValue(pvValue)
{}
bool TestRecord::isSynchronous() {return true;}
void TestRecord::process(
RecordProcessRequesterPtr const &processRequester,bool alreadyLocked)
{
if(!alreadyLocked) lock();
pvValue->put(pvValue->get() + 1);
processRequester->recordProcessResult(Status::Ok);
unlock();
processRequester->recordProcessComplete();
dequeueProcessRequest(processRequester);
}
}}

43
test/record/testRecord.h Normal file
View File

@ -0,0 +1,43 @@
/* testRecord.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
*/
#ifndef TEST_RECORD_H
#define TEST_RECORD_H
#include <string>
#include <cstring>
#include <stdexcept>
#include <memory>
#include <pv/pvDatabase.h>
namespace epics { namespace pvDatabase {
class TestRecord;
class TestRecord :
public virtual PVRecord
{
public:
POINTER_DEFINITIONS(TestRecord);
static PVRecordPtr create(epics::pvData::String const & recordName);
virtual ~TestRecord();
virtual bool isSynchronous();
virtual void process(
epics::pvDatabase::RecordProcessRequesterPtr const &processRequester,
bool alreadyLocked);
private:
TestRecord(epics::pvData::String const & recordName,
epics::pvData::PVStructurePtr const & pvStructure,
epics::pvData::PVLongPtr const &pvValue);
epics::pvData::PVLongPtr pvValue;
};
}}
#endif /* TEST_RECORD_H */

View File

@ -0,0 +1,296 @@
/*testRecordMain.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 <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <memory>
#include <iostream>
#include <epicsStdio.h>
#include <epicsMutex.h>
#include <epicsEvent.h>
#include <epicsThread.h>
#include <epicsExport.h>
#include <pv/pvIntrospect.h>
#include <pv/pvData.h>
#include <pv/pvAccess.h>
#include <pv/event.h>
#include "testRecord.h"
using namespace std;
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::pvDatabase;
class MyPVListener;
typedef std::tr1::shared_ptr<MyPVListener> MyPVListenerPtr;
class MyProcessRequester;
typedef std::tr1::shared_ptr<MyProcessRequester> MyProcessRequesterPtr;
class MyPVListener :
public PVListener,
public std::tr1::enable_shared_from_this<MyPVListener>
{
public:
POINTER_DEFINITIONS(PVListener);
static MyPVListenerPtr create(
String const & requesterName,
PVRecordPtr const & pvRecord,
PVRecordFieldPtr const &pvRecordField)
{
MyPVListenerPtr pvPVListener(
new MyPVListener(requesterName,pvRecord,pvRecordField));
pvPVListener->init();
return pvPVListener;
}
virtual ~MyPVListener() {}
virtual void dataPut(PVRecordFieldPtr const & pvRecordField)
{
String fieldName = pvRecordField->getFullFieldName();
printf("%s dataPut(requested(%s))\n",
requesterName.c_str(),
fieldName.c_str());
}
virtual void dataPut(
PVRecordStructurePtr const & requested,
PVRecordFieldPtr const & pvRecordField)
{
String requestedName = requested->getFullFieldName();
String fieldName = pvRecordField->getFullFieldName();
printf("%s dataPut(requested(%s),pvRecordField(%s))\n",
requesterName.c_str(),
requestedName.c_str(),
fieldName.c_str());
}
virtual void beginGroupPut(PVRecordPtr const & pvRecord)
{
printf("beginGroupPut\n");
}
virtual void endGroupPut(PVRecordPtr const & pvRecord)
{
printf("endGroupPut\n");
}
virtual void unlisten(PVRecordPtr const & pvRecord)
{
printf("unlisten\n");
}
private:
MyPVListenerPtr getPtrSelf()
{
return shared_from_this();
}
MyPVListener(
String const & requesterName,
PVRecordPtr const & pvRecord,
PVRecordFieldPtr const &pvRecordField)
: isDetached(false),
requesterName(requesterName),
pvRecord(pvRecord),
pvRecordField(pvRecordField)
{}
void init() {
pvRecord->addListener(getPtrSelf());
pvRecordField->addListener(getPtrSelf());
}
bool isDetached;
String requesterName;
PVRecordPtr pvRecord;
PVRecordFieldPtr pvRecordField;
};
class MyProcessRequester :
public virtual Requester,
public virtual RecordProcessRequester,
public PVRecordClient,
public std::tr1::enable_shared_from_this<MyProcessRequester>
{
public:
static MyProcessRequesterPtr create(
String const &requesterName,
PVRecordPtr const & pvRecord)
{
MyProcessRequesterPtr pvProcessRequester(
new MyProcessRequester(requesterName,pvRecord));
pvProcessRequester->init();
return pvProcessRequester;
}
bool process()
{
if(isDetached) {
message("process request but detached",errorMessage);
return false;
}
pvRecord->queueProcessRequest(getPtrSelf());
event.wait();
return true;
}
virtual ~MyProcessRequester() {}
virtual void detach(PVRecordPtr const & pvRecord)
{
isDetached = true;
message("detached",infoMessage);
}
virtual String getRequesterName() {return requesterName;}
virtual void message(
String const & message,
MessageType messageType)
{
String messageTypeName = getMessageTypeName(messageType);
printf("%s %s %s\n",
requesterName.c_str(),
message.c_str(),
messageTypeName.c_str());
}
virtual void becomeProcessor()
{
pvRecord->process(getPtrSelf(),false);
}
virtual void recordProcessResult(epics::pvData::Status status)
{
String xxx("recordProcessResult ");
message( xxx + status.getMessage(),infoMessage);
}
virtual void recordProcessComplete()
{
message("recordProcessComplete",infoMessage);
event.signal();
}
private:
MyProcessRequesterPtr getPtrSelf()
{
return shared_from_this();
}
MyProcessRequester(
String const &requesterName,
PVRecordPtr const & pvRecord)
: isDetached(false),
requesterName(requesterName),
pvRecord(pvRecord)
{}
void init() {
pvRecord->addPVRecordClient(getPtrSelf());
pvRecord->addRequester(getPtrSelf());
}
Event event;
bool isDetached;
String requesterName;
PVRecordPtr pvRecord;
};
void dumpPVRecordField(PVRecordFieldPtr pvRecordField)
{
PVRecordStructurePtr pvRecordStructure = pvRecordField->getParent();
PVFieldPtr pvField = pvRecordField->getPVField();
String fieldName = pvField->getFieldName();
String fullFieldName = pvRecordField->getFullFieldName();
String fullName = pvRecordField->getFullName();
PVRecordPtr pvRecord = pvRecordField->getPVRecord();
String recordName = pvRecord->getRecordName();
printf("recordName %s fullName %s fullFieldName %s fieldName %s\n",
recordName.c_str(),
fullName.c_str(),
fullFieldName.c_str(),
fieldName.c_str());
}
void dumpPVRecordStructure(PVRecordStructurePtr pvRecordStructure)
{
dumpPVRecordField(pvRecordStructure);
PVRecordFieldPtrArrayPtr pvRecordFields =
pvRecordStructure->getPVRecordFields();
size_t num = pvRecordFields->size();
for(size_t i=0; i<num; i++) {
PVRecordFieldPtr pvRecordField = (*pvRecordFields.get())[i];
if(pvRecordField->getPVField()->getField()->getType()==structure) {
PVRecordStructurePtr xxx =
static_pointer_cast<PVRecordStructure>(pvRecordField);
dumpPVRecordStructure(xxx);
} else {
dumpPVRecordField(pvRecordField);
}
}
}
int main(int argc,char *argv[])
{
String recordName("testRecord");
PVRecordPtr pvRecord = TestRecord::create(recordName);
dumpPVRecordStructure(pvRecord->getPVRecordStructure());
PVStructurePtr pvStructure =
pvRecord->getPVRecordStructure()->getPVStructure();
PVLongPtr pvValue = pvStructure->getLongField("value");
String builder;
pvStructure->toString(&builder);
printf("pvStructure\n%s\n",builder.c_str());
builder.clear();
pvValue->toString(&builder);
printf("value\n%s\n",builder.c_str());
PVRecordFieldPtr recordFieldValue = pvRecord->findPVRecordField(pvValue);
MyPVListenerPtr listenTop = MyPVListener::create(
"listenTop", pvRecord, pvRecord->getPVRecordStructure());
MyPVListenerPtr listenValue = MyPVListener::create(
"listenValue", pvRecord,recordFieldValue);
PVFieldPtr pvValueAlarm = pvStructure->getSubField("valueAlarm");
PVRecordFieldPtr recordFieldValueAlarm =
pvRecord->findPVRecordField(pvValueAlarm);
MyPVListenerPtr listenValueAlarm = MyPVListener::create(
"listenValueAlarm", pvRecord,recordFieldValueAlarm);
PVIntPtr pvHighAlarmSeverity =
pvStructure->getIntField("valueAlarm.highAlarmSeverity");
PVRecordFieldPtr recordFieldHighAlarmSeverity =
pvRecord->findPVRecordField(pvHighAlarmSeverity);
MyPVListenerPtr listenHighAlarmSeverity = MyPVListener::create(
"listenHighAlarmSeverity", pvRecord,recordFieldHighAlarmSeverity);
MyProcessRequesterPtr process1 =
MyProcessRequester::create("process1",pvRecord);
MyProcessRequesterPtr process2 =
MyProcessRequester::create("process2",pvRecord);
process1->process();
builder.clear();
pvValue->toString(&builder);
printf("%s\n",builder.c_str());
process2->process();
builder.clear();
pvValue->toString(&builder);
printf("%s\n",builder.c_str());
pvHighAlarmSeverity->put(3);
recordFieldHighAlarmSeverity->message("test message",infoMessage);
printf("all done\n");
#ifdef XXXXXX
PVDatabasePtr pvDatabase = PVDatabase::getMaster();
pvDatabase->addRecord(pvRecord);
cout << recordName << "\n";
string str;
while(true) {
cout << "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
#endif
return 0;
}