173 lines
5.6 KiB
C++
173 lines
5.6 KiB
C++
|
#include <memory>
|
||
|
|
||
|
#include <mesytec-mvlc/mesytec-mvlc.h>
|
||
|
#include <mesytec-mvlc/util/signal_handling.h>
|
||
|
#include <mesytec-mnode/mnode_nng_async.h>
|
||
|
#include <mesytec-mnode/mnode_cpp_types.h>
|
||
|
#include "internal/argh.h"
|
||
|
#include "proto/google/rpc/code.pb.h"
|
||
|
#include "proto/mrpc.pb.h"
|
||
|
#include "proto/mvlc.pb.h"
|
||
|
#include "proto/service.pb.h"
|
||
|
|
||
|
using namespace mesytec;
|
||
|
using namespace std::literals;
|
||
|
using namespace mesytec::mnode::cpp_types;
|
||
|
|
||
|
class MVLCService: public mnode::proto::mvlc::MVLCService
|
||
|
{
|
||
|
public:
|
||
|
explicit MVLCService(mesytec::mvlc::MVLC mvlc)
|
||
|
: mvlc_(mvlc)
|
||
|
{ }
|
||
|
|
||
|
void ReadRegister(::google::protobuf::RpcController *controller,
|
||
|
const mnode::proto::mvlc::ReadRegisterRequest *request,
|
||
|
mnode::proto::mvlc::ReadRegisterResponse *response,
|
||
|
::google::protobuf::Closure *done) override
|
||
|
{
|
||
|
spdlog::info("MVLCService::ReadRegister");
|
||
|
u32 value;
|
||
|
if (auto ec = mvlc_.readRegister(request->address(), value))
|
||
|
{
|
||
|
response->mutable_status()->set_code(ec.value());
|
||
|
response->mutable_status()->set_message(ec.message());
|
||
|
controller->SetFailed(ec.message());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
response->set_value(value);
|
||
|
}
|
||
|
|
||
|
done->Run();
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
mesytec::mvlc::MVLC mvlc_;
|
||
|
};
|
||
|
|
||
|
void print_service_descriptors(google::protobuf::Service &service)
|
||
|
{
|
||
|
auto sd = service.GetDescriptor();
|
||
|
spdlog::info("service: full_name={}, index={}, method_count={}",
|
||
|
sd->full_name(), sd->index(), sd->method_count());
|
||
|
|
||
|
for (int i = 0; i < sd->method_count(); ++i)
|
||
|
{
|
||
|
auto md = sd->method(i);
|
||
|
auto it = md->input_type();
|
||
|
auto ot = md->output_type();
|
||
|
spdlog::info(" method: full_name={}, index={}, input_type={}, output_type={}",
|
||
|
md->full_name(), md->index(), it->full_name(), ot->full_name());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct RPCClosure: public google::protobuf::Closure
|
||
|
{
|
||
|
void Run() override { }
|
||
|
};
|
||
|
|
||
|
struct RPCController: public google::protobuf::RpcController
|
||
|
{
|
||
|
void Reset() override { }
|
||
|
bool Failed() const override { return false; }
|
||
|
std::string ErrorText() const override { return ""; }
|
||
|
void StartCancel() override { }
|
||
|
void SetFailed(const std::string &reason) override { }
|
||
|
bool IsCanceled() const override { return false; }
|
||
|
void NotifyOnCancel(google::protobuf::Closure *callback) override { }
|
||
|
};
|
||
|
|
||
|
struct RpcChannel: public google::protobuf::RpcChannel
|
||
|
{
|
||
|
explicit RpcChannel(nng_socket socket)
|
||
|
: socket_(socket)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
int send_request(const mnode::proto::mrpc::MethodCall &methodCall)
|
||
|
{
|
||
|
auto methodCallSize = methodCall.ByteSizeLong();
|
||
|
auto msg = mnode::nng::allocate_message(sizeof(u32) + methodCallSize);
|
||
|
*reinterpret_cast<u32 *>(nng_msg_body(msg.get())) = methodCallSize;
|
||
|
if (!methodCall.SerializeToArray(reinterpret_cast<u8 *>(nng_msg_body(msg.get())) + sizeof(u32), methodCallSize))
|
||
|
{
|
||
|
spdlog::error("methodCall.SerializeToArray failed");
|
||
|
}
|
||
|
spdlog::info("sending request: nng_msg_len={}, methodCallSize={}", nng_msg_len(msg.get()), methodCallSize);
|
||
|
return mnode::nng::send_message(socket_, msg);
|
||
|
}
|
||
|
|
||
|
void CallMethod(const google::protobuf::MethodDescriptor *method,
|
||
|
google::protobuf::RpcController *controller,
|
||
|
const google::protobuf::Message *request,
|
||
|
google::protobuf::Message *response,
|
||
|
google::protobuf::Closure *done) override
|
||
|
{
|
||
|
spdlog::info("RpcChannel::CallMethod: method={}, request={}, response={}",
|
||
|
method->full_name(), request->ShortDebugString(), response->ShortDebugString());
|
||
|
|
||
|
methodCall_.set_service(method->service()->full_name());
|
||
|
methodCall_.set_method(method->full_name());
|
||
|
methodCall_.mutable_request()->PackFrom(*request);
|
||
|
|
||
|
if (auto nng_res = send_request(methodCall_))
|
||
|
{
|
||
|
spdlog::error("nng_sendmsg: {}", nng_strerror(nng_res));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
auto [nng_response, nng_res] = mnode::nng::receive_message(socket_);
|
||
|
|
||
|
if (nng_res)
|
||
|
{
|
||
|
spdlog::error("nng_recvmsg: {}", nng_strerror(nng_res));
|
||
|
return;
|
||
|
}
|
||
|
else if (nng_res == NNG_ETIMEDOUT)
|
||
|
{
|
||
|
spdlog::trace("nng_recvmsg: NNG_ETIMEDOUT");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
auto callResponseSize = mnode::nng::msg_trim_read<u32>(nng_response.get());
|
||
|
}
|
||
|
|
||
|
nng_socket socket_;
|
||
|
mnode::proto::mrpc::MethodCall methodCall_;
|
||
|
mnode::proto::mrpc::MethodCallResponse callResponse_;
|
||
|
|
||
|
};
|
||
|
|
||
|
int main()
|
||
|
{
|
||
|
namespace nng = mnode::nng;
|
||
|
spdlog::set_level(spdlog::level::debug);
|
||
|
auto socket = nng::make_req_socket();
|
||
|
|
||
|
if (int res = nng_dial(socket, "tcp://localhost:5555", nullptr, NNG_FLAG_NONBLOCK))
|
||
|
{
|
||
|
nng::mnode_nng_error("nng_dial", res);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
RPCController rpcController;
|
||
|
RPCClosure done;
|
||
|
RpcChannel rpcChannel(socket);
|
||
|
mnode::proto::mvlc::MVLCService::Stub mvlcService(&rpcChannel);
|
||
|
|
||
|
for (int i = 0; i < 10; ++i)
|
||
|
{
|
||
|
mnode::proto::vme::ReadRequest request;
|
||
|
request.set_address(0xffff600e);
|
||
|
request.mutable_amod()->set_value(mesytec::mvlc::vme_amods::A32);
|
||
|
request.set_data_width(mnode::proto::vme::DataWidth::D32);
|
||
|
mnode::proto::vme::ReadResponse response;
|
||
|
spdlog::info("request: {}", request.ShortDebugString());
|
||
|
mvlcService.VMERead(&rpcController, &request, &response, &done);
|
||
|
spdlog::info("response: {}", response.ShortDebugString());
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|