diff --git a/testApp/remote/eget.cpp b/testApp/remote/eget.cpp index e048a4b..77e2a88 100644 --- a/testApp/remote/eget.cpp +++ b/testApp/remote/eget.cpp @@ -390,21 +390,23 @@ class ChannelGetRequesterImpl : public ChannelGetRequester if (value.get() == 0) { std::cerr << "no 'value' field" << std::endl; - return; - } - - Type valueType = value->getField()->getType(); - if (valueType == scalar) - std::cout << *(value.get()) << std::endl; - else if (valueType == scalarArray) - { - // TODO decide on formatting (with or without std::endl) - formatScalarArray(std::cout, dynamic_pointer_cast(value)) << std::endl; + std::cout << m_channelName << std::endl << *(m_pvStructure.get()) << std::endl << std::endl; } else { - // switch to structure mode - std::cout << m_channelName << std::endl << *(m_pvStructure.get()) << std::endl << std::endl; + Type valueType = value->getField()->getType(); + if (valueType == scalar) + std::cout << *(value.get()) << std::endl; + else if (valueType == scalarArray) + { + // TODO decide on formatting (with or without std::endl) + formatScalarArray(std::cout, dynamic_pointer_cast(value)) << std::endl; + } + else + { + // switch to structure mode + std::cout << m_channelName << std::endl << *(m_pvStructure.get()) << std::endl << std::endl; + } } } else if (mode == TerseMode) @@ -741,9 +743,42 @@ int main (int argc, char *argv[]) if (channelRequesterImpl->waitUntilConnected(timeOut)) { - shared_ptr getRequesterImpl(new ChannelGetRequesterImpl(channel->getChannelName())); - ChannelGet::shared_pointer channelGet = channel->createChannelGet(getRequesterImpl, pvRequest); - allOK &= getRequesterImpl->waitUntilGet(timeOut); + shared_ptr getFieldRequesterImpl; + + // probe for value field + if (mode == ValueOnlyMode) + { + getFieldRequesterImpl.reset(new GetFieldRequesterImpl(channel)); + // get all to be immune to bad clients not supporting selective getField request + channel->getField(getFieldRequesterImpl, ""); + } + + if (getFieldRequesterImpl.get() == 0 || + getFieldRequesterImpl->waitUntilFieldGet(timeOut)) + { + // check probe + if (getFieldRequesterImpl.get()) + { + Structure::const_shared_pointer structure = + dynamic_pointer_cast(getFieldRequesterImpl->getField()); + if (structure.get() == 0 || structure->getField("value").get() == 0) + { + // fallback to structure + mode = StructureMode; + pvRequest = getCreateRequest()->createRequest("field()", requester); + } + } + + shared_ptr getRequesterImpl(new ChannelGetRequesterImpl(channel->getChannelName())); + ChannelGet::shared_pointer channelGet = channel->createChannelGet(getRequesterImpl, pvRequest); + allOK &= getRequesterImpl->waitUntilGet(timeOut); + } + else + { + allOK = false; + channel->destroy(); + std::cerr << "[" << channel->getChannelName() << "] failed to get channel introspection data" << std::endl; + } } else { diff --git a/testApp/remote/pvget.cpp b/testApp/remote/pvget.cpp index 2dc8823..6a51d4d 100644 --- a/testApp/remote/pvget.cpp +++ b/testApp/remote/pvget.cpp @@ -131,25 +131,27 @@ class ChannelGetRequesterImpl : public ChannelGetRequester if (value.get() == 0) { std::cerr << "no 'value' field" << std::endl; - return; - } - - Type valueType = value->getField()->getType(); - if (valueType != scalar && valueType != scalarArray) - { - // switch to structure mode std::cout << m_channelName << std::endl << *(m_pvStructure.get()) << std::endl << std::endl; } else { - if (fieldSeparator == ' ' && value->getField()->getType() == scalar) - std::cout << std::setw(30) << std::left << m_channelName; + Type valueType = value->getField()->getType(); + if (valueType != scalar && valueType != scalarArray) + { + // switch to structure mode + std::cout << m_channelName << std::endl << *(m_pvStructure.get()) << std::endl << std::endl; + } else - std::cout << m_channelName; + { + if (fieldSeparator == ' ' && value->getField()->getType() == scalar) + std::cout << std::setw(30) << std::left << m_channelName; + else + std::cout << m_channelName; - std::cout << fieldSeparator; + std::cout << fieldSeparator; - terse(std::cout, value) << std::endl; + terse(std::cout, value) << std::endl; + } } } else if (mode == TerseMode) @@ -239,26 +241,29 @@ class MonitorRequesterImpl : public MonitorRequester if (value.get() == 0) { std::cerr << "no 'value' field" << std::endl; - return; - } - - Type valueType = value->getField()->getType(); - if (valueType != scalar && valueType != scalarArray) - { - // switch to structure mode std::cout << m_channelName << std::endl; std::cout << *(element->pvStructurePtr.get()) << std::endl << std::endl; } else { - if (fieldSeparator == ' ' && value->getField()->getType() == scalar) - std::cout << std::setw(30) << std::left << m_channelName; + Type valueType = value->getField()->getType(); + if (valueType != scalar && valueType != scalarArray) + { + // switch to structure mode + std::cout << m_channelName << std::endl; + std::cout << *(element->pvStructurePtr.get()) << std::endl << std::endl; + } else - std::cout << m_channelName; + { + if (fieldSeparator == ' ' && value->getField()->getType() == scalar) + std::cout << std::setw(30) << std::left << m_channelName; + else + std::cout << m_channelName; - std::cout << fieldSeparator; + std::cout << fieldSeparator; - terse(std::cout, value) << std::endl; + terse(std::cout, value) << std::endl; + } } } else if (mode == TerseMode) @@ -417,17 +422,50 @@ int main (int argc, char *argv[]) if (channelRequesterImpl->waitUntilConnected(timeOut)) { - if (!monitor) + shared_ptr getFieldRequesterImpl; + + // probe for value field + if (mode == ValueOnlyMode) { - shared_ptr getRequesterImpl(new ChannelGetRequesterImpl(channel->getChannelName())); - ChannelGet::shared_pointer channelGet = channel->createChannelGet(getRequesterImpl, pvRequest); - allOK &= getRequesterImpl->waitUntilGet(timeOut); + getFieldRequesterImpl.reset(new GetFieldRequesterImpl(channel)); + // get all to be immune to bad clients not supporting selective getField request + channel->getField(getFieldRequesterImpl, ""); + } + + if (getFieldRequesterImpl.get() == 0 || + getFieldRequesterImpl->waitUntilFieldGet(timeOut)) + { + // check probe + if (getFieldRequesterImpl.get()) + { + Structure::const_shared_pointer structure = + dynamic_pointer_cast(getFieldRequesterImpl->getField()); + if (structure.get() == 0 || structure->getField("value").get() == 0) + { + // fallback to structure + mode = StructureMode; + pvRequest = getCreateRequest()->createRequest("field()", requester); + } + } + + if (!monitor) + { + shared_ptr getRequesterImpl(new ChannelGetRequesterImpl(channel->getChannelName())); + ChannelGet::shared_pointer channelGet = channel->createChannelGet(getRequesterImpl, pvRequest); + allOK &= getRequesterImpl->waitUntilGet(timeOut); + } + else + { + shared_ptr monitorRequesterImpl(new MonitorRequesterImpl(channel->getChannelName())); + Monitor::shared_pointer monitorGet = channel->createMonitor(monitorRequesterImpl, pvRequest); + allOK &= true; + } } else { - shared_ptr monitorRequesterImpl(new MonitorRequesterImpl(channel->getChannelName())); - Monitor::shared_pointer monitorGet = channel->createMonitor(monitorRequesterImpl, pvRequest); - allOK &= true; + allOK = false; + channel->destroy(); + std::cerr << "[" << channel->getChannelName() << "] failed to get channel introspection data" << std::endl; } } else diff --git a/testApp/remote/pvput.cpp b/testApp/remote/pvput.cpp index 3c80ecb..91d384e 100644 --- a/testApp/remote/pvput.cpp +++ b/testApp/remote/pvput.cpp @@ -649,25 +649,27 @@ class ChannelPutRequesterImpl : public ChannelPutRequester if (value.get() == 0) { std::cerr << "no 'value' field" << std::endl; - return; - } - - Type valueType = value->getField()->getType(); - if (valueType != scalar && valueType != scalarArray) - { - // switch to structure mode - std::cout << m_channelName << std::endl << *(m_pvStructure.get()) << std::endl << std::endl; + std::cout << std::endl << *(m_pvStructure.get()) << std::endl << std::endl; } else { - if (fieldSeparator == ' ' && value->getField()->getType() == scalar) - std::cout << std::setw(30) << std::left << m_channelName; + Type valueType = value->getField()->getType(); + if (valueType != scalar && valueType != scalarArray) + { + // switch to structure mode + std::cout << m_channelName << std::endl << *(m_pvStructure.get()) << std::endl << std::endl; + } else - std::cout << m_channelName; + { + if (fieldSeparator == ' ' && value->getField()->getType() == scalar) + std::cout << std::setw(30) << std::left << m_channelName; + else + std::cout << m_channelName; - std::cout << fieldSeparator; + std::cout << fieldSeparator; - terse(std::cout, value) << std::endl; + terse(std::cout, value) << std::endl; + } } } else if (mode == TerseMode) diff --git a/testApp/remote/pvutils.cpp b/testApp/remote/pvutils.cpp index 6e52209..c2d7792 100644 --- a/testApp/remote/pvutils.cpp +++ b/testApp/remote/pvutils.cpp @@ -175,7 +175,7 @@ char *url_encode(const char *str) { String ChannelRequesterImpl::getRequesterName() { return "ChannelRequesterImpl"; -}; +} void ChannelRequesterImpl::message(String const & message, MessageType messageType) { @@ -216,3 +216,57 @@ bool ChannelRequesterImpl::waitUntilConnected(double timeOut) { return m_event.wait(timeOut); } + + + +GetFieldRequesterImpl::GetFieldRequesterImpl(epics::pvAccess::Channel::shared_pointer channel) : + m_channel(channel) +{ + +} + +String GetFieldRequesterImpl::getRequesterName() +{ + return "GetFieldRequesterImpl"; +} + +void GetFieldRequesterImpl::message(String const & message, MessageType messageType) +{ + std::cerr << "[" << getRequesterName() << "] message(" << message << ", " << getMessageTypeName(messageType) << ")" << std::endl; +} + +void GetFieldRequesterImpl::getDone(const epics::pvData::Status& status, epics::pvData::FieldConstPtr const & field) +{ + if (status.isSuccess()) + { + // show warning + if (!status.isOK()) + { + std::cerr << "[" << m_channel->getChannelName() << "] getField create: " << status.toString() << std::endl; + } + + // assign smart pointers + { + Lock lock(m_pointerMutex); + m_field = field; + } + } + else + { + // do not complain about missing field + //std::cerr << "[" << m_channel->getChannelName() << "] failed to get channel introspection data: " << status.toString() << std::endl; + } + + m_event.signal(); +} + +bool GetFieldRequesterImpl::waitUntilFieldGet(double timeOut) +{ + return m_event.wait(timeOut); +} + +epics::pvData::FieldConstPtr GetFieldRequesterImpl::getField() +{ + Lock lock(m_pointerMutex); + return m_field; +} diff --git a/testApp/remote/pvutils.h b/testApp/remote/pvutils.h index 1369b4c..21ba4cf 100644 --- a/testApp/remote/pvutils.h +++ b/testApp/remote/pvutils.h @@ -52,3 +52,27 @@ class ChannelRequesterImpl : bool waitUntilConnected(double timeOut); }; + +class GetFieldRequesterImpl : + public epics::pvAccess::GetFieldRequester +{ + private: + epics::pvAccess::Channel::shared_pointer m_channel; + epics::pvData::FieldConstPtr m_field; + epics::pvData::Event m_event; + epics::pvData::Mutex m_pointerMutex; + + public: + + GetFieldRequesterImpl(epics::pvAccess::Channel::shared_pointer channel); + + virtual epics::pvData::String getRequesterName(); + virtual void message(epics::pvData::String const & message, epics::pvData::MessageType messageType); + + virtual void getDone(const epics::pvData::Status& status, epics::pvData::FieldConstPtr const & field); + + epics::pvData::FieldConstPtr getField(); + + bool waitUntilFieldGet(double timeOut); +}; +