diff --git a/ADApp/pluginSrc/NDPluginPva.cpp b/ADApp/pluginSrc/NDPluginPva.cpp index 0377cd810..cdfbfe9be 100644 --- a/ADApp/pluginSrc/NDPluginPva.cpp +++ b/ADApp/pluginSrc/NDPluginPva.cpp @@ -2,9 +2,10 @@ #include #include -#include +#include +#include +#include #include -#include #include @@ -16,74 +17,85 @@ static const char *driverName="NDPluginPva"; -using namespace epics; -using namespace epics::pvData; -using namespace epics::pvAccess; -using namespace epics::pvDatabase; -using namespace epics::nt; -using namespace std; - -class NDPLUGIN_API NTNDArrayRecord : - public PVRecord -{ - -private: - NTNDArrayRecord(string const & name, PVStructurePtr const & pvStructure) - :PVRecord(name, pvStructure) {} - - NTNDArrayPtr m_ntndArray; - NTNDArrayConverterPtr m_converter; - -public: - POINTER_DEFINITIONS(NTNDArrayRecord); - - virtual ~NTNDArrayRecord () {} - static NTNDArrayRecordPtr create (string const & name); - virtual bool init (); - virtual void process () {} - void update (NDArray *pArray); +namespace pvd = epics::pvData; +namespace pva = epics::pvAccess; +namespace nt = epics::nt; + +namespace { +/* pvDatabase compatibility + * Sends all fields which are assigned by NTNDArrayConverter, + * regardless of whether they change. + */ +struct BitMarker : public pvd::PostHandler { + const pvd::PVFieldPtr fld; + const pvd::BitSetPtr mask; + + BitMarker(const pvd::PVFieldPtr& fld, + const pvd::BitSetPtr& mask) + :fld(fld) + ,mask(mask) + {} + virtual ~BitMarker() {} + + virtual void postPut() OVERRIDE FINAL + { + mask->set(fld->getFieldOffset()); + } }; - -NTNDArrayRecordPtr NTNDArrayRecord::create (string const & name) -{ - NTNDArrayBuilderPtr builder = NTNDArray::createBuilder(); - builder->addDescriptor()->addTimeStamp()->addAlarm()->addDisplay(); - - NTNDArrayRecordPtr pvRecord(new NTNDArrayRecord(name, - builder->createPVStructure())); - - if(!pvRecord->init()) - pvRecord.reset(); - - return pvRecord; -} - -bool NTNDArrayRecord::init () -{ - initPVRecord(); - m_ntndArray = NTNDArray::wrap(getPVStructure()); - m_converter.reset(new NTNDArrayConverter(m_ntndArray)); - return true; } -void NTNDArrayRecord::update(NDArray *pArray) +class NTNDArrayRecord { - lock(); - - try +public: + pvas::StaticProvider provider; + pvas::SharedPV::shared_pointer pv; + + const pvd::PVStructurePtr current; + // wraps 'current' + const nt::NTNDArrayPtr m_ntndArray; + NTNDArrayConverter m_converter; + + pvd::BitSetPtr changes; + + NTNDArrayRecord(const std::string& name) + :provider(pvas::StaticProvider(name)) + ,current(nt::NTNDArray::createBuilder() + ->addDescriptor()->addTimeStamp()->addAlarm()->addDisplay() + ->createPVStructure()) + ,m_ntndArray(nt::NTNDArray::wrap(current)) + ,m_converter(m_ntndArray) + ,changes(new pvd::BitSet(current->getNumberFields())) { - beginGroupPut(); - m_converter->fromArray(pArray); - endGroupPut(); + pvas::SharedPV::Config pv_conf; + // pvDatabase compatibility mode for pvRequest handling + pv_conf.mapperMode = pvd::PVRequestMapper::Slice; + + pv = pvas::SharedPV::buildReadOnly(&pv_conf); + pv->open(*current); + provider.add(name, pv); + + { + const pvd::PVFieldPtrArray& fields(current->getPVFields()); + for(size_t i=0, N=fields.size(); i temp(new BitMarker(fields[i], changes)); + fields[i]->setPostHandler(temp); + } + } } - catch(...) + + void update(NDArray *pArray) { - endGroupPut(); - unlock(); - throw; + changes->clear(); + // through several levels of indirection, updates this->current + // and through several more, updates this->changes + m_converter.fromArray(pArray); + + // SharedPV::post() makes a lightweight copy of *current, + // so we may safely continue to change it. + + pv->post(*current, *changes); } - unlock(); -} +}; /** Callback function that is called by the NDArray driver with new NDArray * data. @@ -155,12 +167,12 @@ NDPluginPva::NDPluginPva(const char *portName, int queueSize, : NDPluginDriver(portName, queueSize, blockingCallbacks, NDArrayPort, NDArrayAddr, 1, maxBuffers, maxMemory, 0, 0, 0, 1, priority, stackSize, 1, true), - m_record(NTNDArrayRecord::create(pvName)) + m_record(new NTNDArrayRecord(pvName)) { createParam(NDPluginPvaPvNameString, asynParamOctet, &NDPluginPvaPvName); if(!m_record.get()) - throw runtime_error("failed to create NTNDArrayRecord"); + throw std::runtime_error("failed to create NTNDArrayRecord"); /* Set the plugin type string */ setStringParam(NDPluginDriverPluginType, "NDPluginPva"); @@ -171,13 +183,12 @@ NDPluginPva::NDPluginPva(const char *portName, int queueSize, /* Try to connect to the NDArray port */ connectToArrayPort(); - PVDatabasePtr master = PVDatabase::getMaster(); - ChannelProviderLocalPtr channelProvider = getChannelProviderLocal(); - - if(!master->addRecord(m_record)) - throw runtime_error("couldn't add record to master database"); + pva::ChannelProviderRegistry::servers() + ->addSingleton(m_record->provider.provider()); } +NDPluginPva::~NDPluginPva() {} + /* Configuration routine. Called directly, or from the iocsh function */ extern "C" int NDPvaConfigure(const char *portName, int queueSize, int blockingCallbacks, const char *NDArrayPort, int NDArrayAddr, diff --git a/ADApp/pluginSrc/NDPluginPva.h b/ADApp/pluginSrc/NDPluginPva.h index 39f3c88cc..b705a6165 100644 --- a/ADApp/pluginSrc/NDPluginPva.h +++ b/ADApp/pluginSrc/NDPluginPva.h @@ -23,6 +23,7 @@ class NDPLUGIN_API NDPluginPva : public NDPluginDriver, NDPluginPva(const char *portName, int queueSize, int blockingCallbacks, const char *NDArrayPort, int NDArrayAddr, const char *pvName, int maxBuffers, size_t maxMemory, int priority, int stackSize); + virtual ~NDPluginPva(); /* These methods override the virtual methods in the base class */ void processCallbacks(NDArray *pArray);