diff --git a/pdbApp/pdbsingle.cpp b/pdbApp/pdbsingle.cpp index 728bd8e..9173c65 100644 --- a/pdbApp/pdbsingle.cpp +++ b/pdbApp/pdbsingle.cpp @@ -108,9 +108,11 @@ PDBSinglePut::PDBSinglePut(PDBSingleChannel::shared_pointer channel, void PDBSinglePut::put(pvd::PVStructure::shared_pointer const & value, pvd::BitSet::shared_pointer const & changed) { + // assume value may be a different struct each time + std::auto_ptr putpvif(PVIF::attach(channel->pv->chan, value)); { DBScanLocker L(channel->pv->chan); - pvif->get(*changed); + putpvif->get(*changed); } requester->putDone(pvd::Status(), shared_from_this()); } diff --git a/testApp/testpdb.cpp b/testApp/testpdb.cpp index 390f74b..e484097 100644 --- a/testApp/testpdb.cpp +++ b/testApp/testpdb.cpp @@ -28,6 +28,52 @@ void testFieldEqual(const pvd::PVStructurePtr& val, const char *name, typename P } } +struct PVPut +{ + TestChannelRequester::shared_pointer chreq; + pva::Channel::shared_pointer chan; + TestChannelFieldRequester::shared_pointer fldreq; + TestChannelPutRequester::shared_pointer putreq; + pva::ChannelPut::shared_pointer chput; + pvd::PVStructurePtr putval; + pvd::BitSetPtr putchanged; + + PVPut(const pva::ChannelProvider::shared_pointer& prov, const char *name) + :chreq(new TestChannelRequester()) + ,chan(prov->createChannel(name, chreq)) + ,fldreq(new TestChannelFieldRequester()) + ,putreq(new TestChannelPutRequester()) + { + if(!chan || !chan->isConnected()) + throw std::runtime_error("channel not connected"); + chan->getField(fldreq, ""); + if(!fldreq->done || !fldreq->fielddesc || fldreq->fielddesc->getType()!=pvd::structure) + throw std::runtime_error("Failed to get fielddesc"); + putval = pvd::getPVDataCreate()->createPVStructure(std::tr1::static_pointer_cast(fldreq->fielddesc)); + chput = chan->createChannelPut(putreq, putval); + if(!chput) + throw std::runtime_error("Failed to create put op"); + putchanged.reset(new pvd::BitSet()); + } + ~PVPut() { + chput->destroy(); + chan->destroy(); + } + void put() { + putreq->donePut = false; + chput->put(putval, putchanged); + if(!putreq->donePut) + throw std::runtime_error("Put operation fails"); + } + pvd::PVStructurePtr get() { + putreq->doneGet = false; + chput->get(); + if(!putreq->doneGet || !putreq->value) + throw std::runtime_error("Get operation fails"); + return putreq->value; + } +}; + pvd::PVStructurePtr pvget(const pva::ChannelProvider::shared_pointer& prov, const char *name, bool atomic) { @@ -108,6 +154,27 @@ void testGroupGet(const PDBProvider::shared_pointer& prov) testFieldEqual(value, "fld4.value", 40); } +void testSinglePut(const PDBProvider::shared_pointer& prov) +{ + testDiag("test single put"); + + testdbPutFieldOk("rec1", DBR_DOUBLE, 1.0); + + PVPut put(prov, "rec1.VAL"); + + pvd::PVDoublePtr val(put.putval->getSubFieldT("value")); + val->put(2.0); + put.putchanged->clear(); + put.put(); + + testdbGetFieldEqual("rec1", DBR_DOUBLE, 1.0); + + put.putchanged->set(val->getFieldOffset()); + put.put(); + + testdbGetFieldEqual("rec1", DBR_DOUBLE, 2.0); +} + } // namespace extern "C" @@ -129,6 +196,8 @@ MAIN(testpdb) PDBProvider::shared_pointer prov(new PDBProvider()); testSingleGet(prov); testGroupGet(prov); + + testSinglePut(prov); } testDiag("check to see that all dbChannel are closed before IOC shuts down"); testEqual(epics::atomic::get(PDBGroupPV::ninstances), 0u); diff --git a/testApp/utilities.cpp b/testApp/utilities.cpp index 77b2690..4e96d16 100644 --- a/testApp/utilities.cpp +++ b/testApp/utilities.cpp @@ -102,6 +102,47 @@ void TestChannelGetRequester::getDone(const epics::pvData::Status &status, done = true; } +TestChannelPutRequester::TestChannelPutRequester() + :connected(false) + ,doneGet(false) + ,donePut(false) +{} +TestChannelPutRequester::~TestChannelPutRequester() {} + +void TestChannelPutRequester::channelPutConnect( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPut::shared_pointer const & channelPut, + epics::pvData::Structure::const_shared_pointer const & structure) +{ + statusConnect = status; + put = channelPut; + fielddesc = structure; + connected = true; +} + +void TestChannelPutRequester::putDone( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPut::shared_pointer const & channelPut) +{ + statusPut = status; + put = channelPut; + donePut = true; +} + +void TestChannelPutRequester::getDone( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPut::shared_pointer const & channelPut, + epics::pvData::PVStructure::shared_pointer const & pvStructure, + epics::pvData::BitSet::shared_pointer const & bitSet) +{ + statusGet = status; + put = channelPut; + value = pvStructure; + changed = bitSet; + doneGet = true; +} + + static size_t countTestChannelMonitorRequester; TestChannelMonitorRequester::TestChannelMonitorRequester() diff --git a/testApp/utilities.h b/testApp/utilities.h index a95be38..6796a22 100644 --- a/testApp/utilities.h +++ b/testApp/utilities.h @@ -98,6 +98,28 @@ struct TestChannelRequester : public epics::pvAccess::ChannelRequester bool waitForConnect(); }; +struct TestChannelFieldRequester : public epics::pvAccess::GetFieldRequester +{ + POINTER_DEFINITIONS(TestChannelFieldRequester); + DUMBREQUESTER(TestChannelFieldRequester) + + bool done; + epics::pvData::Status status; + epics::pvData::FieldConstPtr fielddesc; + + TestChannelFieldRequester() :done(false) {} + virtual ~TestChannelFieldRequester() {} + + virtual void getDone( + const epics::pvData::Status& status, + epics::pvData::FieldConstPtr const & field) + { + this->status = status; + fielddesc = field; + done = true; + } +}; + struct TestChannelGetRequester : public epics::pvAccess::ChannelGetRequester { POINTER_DEFINITIONS(TestChannelGetRequester); @@ -125,6 +147,37 @@ struct TestChannelGetRequester : public epics::pvAccess::ChannelGetRequester epics::pvData::BitSet::shared_pointer const & bitSet); }; +struct TestChannelPutRequester : public epics::pvAccess::ChannelPutRequester +{ + POINTER_DEFINITIONS(TestChannelPutRequester); + DUMBREQUESTER(TestChannelPutRequester) + + bool connected, doneGet, donePut; + epics::pvData::Status statusConnect, statusPut, statusGet; + epics::pvAccess::ChannelPut::shared_pointer put; + epics::pvData::Structure::const_shared_pointer fielddesc; + epics::pvData::PVStructure::shared_pointer value; + epics::pvData::BitSet::shared_pointer changed; + + TestChannelPutRequester(); + virtual ~TestChannelPutRequester(); + + virtual void channelPutConnect( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPut::shared_pointer const & channelPut, + epics::pvData::Structure::const_shared_pointer const & structure); + + virtual void putDone( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPut::shared_pointer const & channelPut); + + virtual void getDone( + const epics::pvData::Status& status, + epics::pvAccess::ChannelPut::shared_pointer const & channelPut, + epics::pvData::PVStructure::shared_pointer const & pvStructure, + epics::pvData::BitSet::shared_pointer const & bitSet); +}; + struct TestChannelMonitorRequester : public epics::pvData::MonitorRequester { POINTER_DEFINITIONS(TestChannelMonitorRequester);