/** * Copyright - See the COPYRIGHT that is included with this distribution. * EPICS pvAccessCPP is distributed subject to a Software License Agreement * found in file LICENSE that is included with this distribution. */ #include #include #include #include #include #include #define epicsExportSharedSymbols #include #include #include #include #include "pv/rpcClient.h" #if 0 # define TRACE(msg) std::cerr<<"TRACE: "<lastRequest(); operation->request(args); } event.signal(); } virtual void requestDone( const pvd::Status& status, ChannelRPC::shared_pointer const & operation, pvd::PVStructure::shared_pointer const & pvResponse) { TRACE("status="<getProvider("pva"); if(!m_provider) throw std::logic_error("Unknown Provider"); m_channel = m_provider->createChannel(serviceName, DefaultChannelRequester::build(), ChannelProvider::PRIORITY_DEFAULT, address); if(!m_channel) throw std::logic_error("provider createChannel() succeeds w/ NULL Channel"); m_rpc_requester.reset(new RPCRequester); m_rpc = m_channel->createChannelRPC(m_rpc_requester, m_pvRequest); if(!m_rpc) throw std::logic_error("channel createChannelRPC() NULL"); } void RPCClient::destroy() { if (m_channel) { m_channel->destroy(); m_channel.reset(); } if (m_rpc) { m_rpc->destroy(); m_rpc.reset(); } } bool RPCClient::connect(double timeout) { issueConnect(); return waitConnect(timeout); } void RPCClient::issueConnect() { } bool RPCClient::waitConnect(double timeout) { pvd::Lock L(m_rpc_requester->mutex); TRACE("timeout="<conn_status.isSuccess()) { L.unlock(); if(!m_rpc_requester->event.wait(timeout)) { TRACE("TIMEOUT"); return false; } L.lock(); } TRACE("Connected"); return true; } pvd::PVStructure::shared_pointer RPCClient::request( pvd::PVStructure::shared_pointer const & pvArgument, double timeout, bool lastRequest) { if (connect(timeout)) { issueRequest(pvArgument, lastRequest); return waitResponse(timeout); // TODO reduce timeout for a time spent on connect } else throw epics::pvAccess::RPCRequestException(pvd::Status::STATUSTYPE_ERROR, "connection timeout"); } void RPCClient::issueRequest( pvd::PVStructure::shared_pointer const & pvArgument, bool lastRequest) { { pvd::Lock L(m_rpc_requester->mutex); TRACE("conn_status="<conn_status <<" resp_status="<resp_status <<" args:\n"<inprogress) throw std::logic_error("Request already in progress"); m_rpc_requester->inprogress = true; m_rpc_requester->resp_status = pvd::Status::error("No Data"); if(!m_rpc_requester->conn_status.isSuccess()) { TRACE("defer"); m_rpc_requester->last = lastRequest; m_rpc_requester->next_args = pvArgument; return; } TRACE("request args: "<lastRequest(); m_rpc->request(pvArgument); } pvd::PVStructure::shared_pointer RPCClient::waitResponse(double timeout) { pvd::Lock L(m_rpc_requester->mutex); TRACE("timeout="<inprogress) throw std::logic_error("No request in progress"); while(m_rpc_requester->inprogress) { L.unlock(); if(!m_rpc_requester->event.wait(timeout)) { TRACE("TIMEOUT"); throw RPCRequestException(pvd::Status::STATUSTYPE_ERROR, "RPC timeout"); } L.lock(); } TRACE("Complete: conn_status="<conn_status <<" resp_status="<resp_status <<" data:\n"<last_data); if(!m_rpc_requester->conn_status.isSuccess()) throw RPCRequestException(pvd::Status::STATUSTYPE_ERROR, m_rpc_requester->conn_status.getMessage()); if(!m_rpc_requester->resp_status.isSuccess()) throw RPCRequestException(pvd::Status::STATUSTYPE_ERROR, m_rpc_requester->resp_status.getMessage()); // consume last_data so that we can't possibly return it twice pvd::PVStructure::shared_pointer data; data.swap(m_rpc_requester->last_data); if(!data) throw std::logic_error("No reply data?!?"); // copy it so that the caller need not worry about whether it will overwritten // when the next request is issued pvd::PVStructure::shared_pointer ret(pvd::getPVDataCreate()->createPVStructure(data->getStructure())); ret->copyUnchecked(*data); return ret; } RPCClient::shared_pointer RPCClient::create(const std::string & serviceName, pvd::PVStructure::shared_pointer const & pvRequest) { return RPCClient::shared_pointer(new RPCClient(serviceName, pvRequest)); } pvd::PVStructure::shared_pointer RPCClient::sendRequest(const std::string & serviceName, pvd::PVStructure::shared_pointer const & queryRequest, double timeOut) { RPCClient client(serviceName, queryRequest); return client.request(queryRequest, timeOut); } }}// namespace epics::pvAccess