Initial commit: HC900 Crawler

Honeywell HC900을 Modbus TCP로 직접 폴링 → gRPC → C# 크롤러 → PostgreSQL.
기존 Experion OPC UA 데이터 경로를 HC900 직접 통신으로 대체.

- industrial-comm/cpp: C++ Modbus 게이트웨이 (gRPC 서버)
- src: C# .NET 8 ASP.NET Core 크롤러 + 웹 UI (3-Layer)
- mcp-server: Python FastMCP (RAG/NL2SQL/P&ID)
- 다중 컨트롤러(N-Controller) 지원

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
windpacer
2026-06-03 20:28:14 +09:00
commit 16fc7a2598
325 changed files with 126583 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
cmake_minimum_required(VERSION 3.20)
project(comm_core)
add_library(comm_core SHARED)
target_sources(comm_core
PRIVATE
src/controller.cpp
src/codec.cpp
)
target_include_directories(comm_core
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_compile_options(comm_core
PRIVATE
-Wall -Wextra -Wpedantic
)
# ─── HC900 Gateway ───
set(GRPC_DIR /tmp/grpc_local)
set(ABSL_DIR /tmp/absl_local)
set(PROTO_GEN_DIR ${CMAKE_CURRENT_SOURCE_DIR}/gen)
add_executable(hc900_gateway)
target_sources(hc900_gateway
PRIVATE
src/gateway.cpp
src/modbus_tcp.cpp
${PROTO_GEN_DIR}/modbus_gateway.pb.cc
${PROTO_GEN_DIR}/modbus_gateway.grpc.pb.cc
)
target_include_directories(hc900_gateway
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${PROTO_GEN_DIR}
${GRPC_DIR}/usr/include
${ABSL_DIR}/usr/include
)
target_link_directories(hc900_gateway
PRIVATE
${GRPC_DIR}/usr/lib/aarch64-linux-gnu
${ABSL_DIR}/usr/lib/aarch64-linux-gnu
/usr/lib/aarch64-linux-gnu
/lib/aarch64-linux-gnu
)
target_link_libraries(hc900_gateway
PRIVATE
comm_core
grpc++
grpc
gpr
upb
address_sorting
protobuf
absl_synchronization
absl_status
absl_cord
absl_cord_internal
absl_cordz_info
absl_cordz_handle
absl_cordz_functions
absl_cordz_sample_token
absl_hashtablez_sampler
absl_exponential_biased
absl_raw_hash_set
absl_hash
absl_city
absl_low_level_hash
absl_int128
absl_raw_logging_internal
absl_log_severity
absl_spinlock_wait
absl_malloc_internal
absl_throw_delegate
absl_time
absl_time_zone
absl_strings
absl_strings_internal
absl_base
pthread
rt
dl
)
target_compile_options(hc900_gateway
PRIVATE
-Wall -Wextra -Wpedantic
)

View File

@@ -0,0 +1,247 @@
// Generated by the gRPC C++ plugin.
// If you make any local change, they will be lost.
// source: modbus_gateway.proto
#include "modbus_gateway.pb.h"
#include "modbus_gateway.grpc.pb.h"
#include <functional>
#include <grpcpp/support/async_stream.h>
#include <grpcpp/support/async_unary_call.h>
#include <grpcpp/impl/channel_interface.h>
#include <grpcpp/impl/client_unary_call.h>
#include <grpcpp/support/client_callback.h>
#include <grpcpp/support/message_allocator.h>
#include <grpcpp/support/method_handler.h>
#include <grpcpp/impl/rpc_service_method.h>
#include <grpcpp/support/server_callback.h>
#include <grpcpp/impl/codegen/server_callback_handlers.h>
#include <grpcpp/server_context.h>
#include <grpcpp/impl/service_type.h>
#include <grpcpp/support/sync_stream.h>
namespace hc900 {
static const char* ModbusGateway_method_names[] = {
"/hc900.ModbusGateway/ReadTags",
"/hc900.ModbusGateway/WriteTag",
"/hc900.ModbusGateway/StreamTags",
"/hc900.ModbusGateway/ListTags",
"/hc900.ModbusGateway/HealthCheck",
};
std::unique_ptr< ModbusGateway::Stub> ModbusGateway::NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) {
(void)options;
std::unique_ptr< ModbusGateway::Stub> stub(new ModbusGateway::Stub(channel, options));
return stub;
}
ModbusGateway::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options)
: channel_(channel), rpcmethod_ReadTags_(ModbusGateway_method_names[0], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel)
, rpcmethod_WriteTag_(ModbusGateway_method_names[1], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel)
, rpcmethod_StreamTags_(ModbusGateway_method_names[2], options.suffix_for_stats(),::grpc::internal::RpcMethod::SERVER_STREAMING, channel)
, rpcmethod_ListTags_(ModbusGateway_method_names[3], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel)
, rpcmethod_HealthCheck_(ModbusGateway_method_names[4], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel)
{}
::grpc::Status ModbusGateway::Stub::ReadTags(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest& request, ::hc900::ReadTagsResponse* response) {
return ::grpc::internal::BlockingUnaryCall< ::hc900::ReadTagsRequest, ::hc900::ReadTagsResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), rpcmethod_ReadTags_, context, request, response);
}
void ModbusGateway::Stub::async::ReadTags(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest* request, ::hc900::ReadTagsResponse* response, std::function<void(::grpc::Status)> f) {
::grpc::internal::CallbackUnaryCall< ::hc900::ReadTagsRequest, ::hc900::ReadTagsResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_ReadTags_, context, request, response, std::move(f));
}
void ModbusGateway::Stub::async::ReadTags(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest* request, ::hc900::ReadTagsResponse* response, ::grpc::ClientUnaryReactor* reactor) {
::grpc::internal::ClientCallbackUnaryFactory::Create< ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_ReadTags_, context, request, response, reactor);
}
::grpc::ClientAsyncResponseReader< ::hc900::ReadTagsResponse>* ModbusGateway::Stub::PrepareAsyncReadTagsRaw(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest& request, ::grpc::CompletionQueue* cq) {
return ::grpc::internal::ClientAsyncResponseReaderHelper::Create< ::hc900::ReadTagsResponse, ::hc900::ReadTagsRequest, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), cq, rpcmethod_ReadTags_, context, request);
}
::grpc::ClientAsyncResponseReader< ::hc900::ReadTagsResponse>* ModbusGateway::Stub::AsyncReadTagsRaw(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest& request, ::grpc::CompletionQueue* cq) {
auto* result =
this->PrepareAsyncReadTagsRaw(context, request, cq);
result->StartCall();
return result;
}
::grpc::Status ModbusGateway::Stub::WriteTag(::grpc::ClientContext* context, const ::hc900::WriteTagRequest& request, ::hc900::WriteTagResponse* response) {
return ::grpc::internal::BlockingUnaryCall< ::hc900::WriteTagRequest, ::hc900::WriteTagResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), rpcmethod_WriteTag_, context, request, response);
}
void ModbusGateway::Stub::async::WriteTag(::grpc::ClientContext* context, const ::hc900::WriteTagRequest* request, ::hc900::WriteTagResponse* response, std::function<void(::grpc::Status)> f) {
::grpc::internal::CallbackUnaryCall< ::hc900::WriteTagRequest, ::hc900::WriteTagResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_WriteTag_, context, request, response, std::move(f));
}
void ModbusGateway::Stub::async::WriteTag(::grpc::ClientContext* context, const ::hc900::WriteTagRequest* request, ::hc900::WriteTagResponse* response, ::grpc::ClientUnaryReactor* reactor) {
::grpc::internal::ClientCallbackUnaryFactory::Create< ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_WriteTag_, context, request, response, reactor);
}
::grpc::ClientAsyncResponseReader< ::hc900::WriteTagResponse>* ModbusGateway::Stub::PrepareAsyncWriteTagRaw(::grpc::ClientContext* context, const ::hc900::WriteTagRequest& request, ::grpc::CompletionQueue* cq) {
return ::grpc::internal::ClientAsyncResponseReaderHelper::Create< ::hc900::WriteTagResponse, ::hc900::WriteTagRequest, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), cq, rpcmethod_WriteTag_, context, request);
}
::grpc::ClientAsyncResponseReader< ::hc900::WriteTagResponse>* ModbusGateway::Stub::AsyncWriteTagRaw(::grpc::ClientContext* context, const ::hc900::WriteTagRequest& request, ::grpc::CompletionQueue* cq) {
auto* result =
this->PrepareAsyncWriteTagRaw(context, request, cq);
result->StartCall();
return result;
}
::grpc::ClientReader< ::hc900::TagValue>* ModbusGateway::Stub::StreamTagsRaw(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request) {
return ::grpc::internal::ClientReaderFactory< ::hc900::TagValue>::Create(channel_.get(), rpcmethod_StreamTags_, context, request);
}
void ModbusGateway::Stub::async::StreamTags(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest* request, ::grpc::ClientReadReactor< ::hc900::TagValue>* reactor) {
::grpc::internal::ClientCallbackReaderFactory< ::hc900::TagValue>::Create(stub_->channel_.get(), stub_->rpcmethod_StreamTags_, context, request, reactor);
}
::grpc::ClientAsyncReader< ::hc900::TagValue>* ModbusGateway::Stub::AsyncStreamTagsRaw(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request, ::grpc::CompletionQueue* cq, void* tag) {
return ::grpc::internal::ClientAsyncReaderFactory< ::hc900::TagValue>::Create(channel_.get(), cq, rpcmethod_StreamTags_, context, request, true, tag);
}
::grpc::ClientAsyncReader< ::hc900::TagValue>* ModbusGateway::Stub::PrepareAsyncStreamTagsRaw(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request, ::grpc::CompletionQueue* cq) {
return ::grpc::internal::ClientAsyncReaderFactory< ::hc900::TagValue>::Create(channel_.get(), cq, rpcmethod_StreamTags_, context, request, false, nullptr);
}
::grpc::Status ModbusGateway::Stub::ListTags(::grpc::ClientContext* context, const ::hc900::ListTagsRequest& request, ::hc900::ListTagsResponse* response) {
return ::grpc::internal::BlockingUnaryCall< ::hc900::ListTagsRequest, ::hc900::ListTagsResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), rpcmethod_ListTags_, context, request, response);
}
void ModbusGateway::Stub::async::ListTags(::grpc::ClientContext* context, const ::hc900::ListTagsRequest* request, ::hc900::ListTagsResponse* response, std::function<void(::grpc::Status)> f) {
::grpc::internal::CallbackUnaryCall< ::hc900::ListTagsRequest, ::hc900::ListTagsResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_ListTags_, context, request, response, std::move(f));
}
void ModbusGateway::Stub::async::ListTags(::grpc::ClientContext* context, const ::hc900::ListTagsRequest* request, ::hc900::ListTagsResponse* response, ::grpc::ClientUnaryReactor* reactor) {
::grpc::internal::ClientCallbackUnaryFactory::Create< ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_ListTags_, context, request, response, reactor);
}
::grpc::ClientAsyncResponseReader< ::hc900::ListTagsResponse>* ModbusGateway::Stub::PrepareAsyncListTagsRaw(::grpc::ClientContext* context, const ::hc900::ListTagsRequest& request, ::grpc::CompletionQueue* cq) {
return ::grpc::internal::ClientAsyncResponseReaderHelper::Create< ::hc900::ListTagsResponse, ::hc900::ListTagsRequest, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), cq, rpcmethod_ListTags_, context, request);
}
::grpc::ClientAsyncResponseReader< ::hc900::ListTagsResponse>* ModbusGateway::Stub::AsyncListTagsRaw(::grpc::ClientContext* context, const ::hc900::ListTagsRequest& request, ::grpc::CompletionQueue* cq) {
auto* result =
this->PrepareAsyncListTagsRaw(context, request, cq);
result->StartCall();
return result;
}
::grpc::Status ModbusGateway::Stub::HealthCheck(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest& request, ::hc900::HealthCheckResponse* response) {
return ::grpc::internal::BlockingUnaryCall< ::hc900::HealthCheckRequest, ::hc900::HealthCheckResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), rpcmethod_HealthCheck_, context, request, response);
}
void ModbusGateway::Stub::async::HealthCheck(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest* request, ::hc900::HealthCheckResponse* response, std::function<void(::grpc::Status)> f) {
::grpc::internal::CallbackUnaryCall< ::hc900::HealthCheckRequest, ::hc900::HealthCheckResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_HealthCheck_, context, request, response, std::move(f));
}
void ModbusGateway::Stub::async::HealthCheck(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest* request, ::hc900::HealthCheckResponse* response, ::grpc::ClientUnaryReactor* reactor) {
::grpc::internal::ClientCallbackUnaryFactory::Create< ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_HealthCheck_, context, request, response, reactor);
}
::grpc::ClientAsyncResponseReader< ::hc900::HealthCheckResponse>* ModbusGateway::Stub::PrepareAsyncHealthCheckRaw(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest& request, ::grpc::CompletionQueue* cq) {
return ::grpc::internal::ClientAsyncResponseReaderHelper::Create< ::hc900::HealthCheckResponse, ::hc900::HealthCheckRequest, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), cq, rpcmethod_HealthCheck_, context, request);
}
::grpc::ClientAsyncResponseReader< ::hc900::HealthCheckResponse>* ModbusGateway::Stub::AsyncHealthCheckRaw(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest& request, ::grpc::CompletionQueue* cq) {
auto* result =
this->PrepareAsyncHealthCheckRaw(context, request, cq);
result->StartCall();
return result;
}
ModbusGateway::Service::Service() {
AddMethod(new ::grpc::internal::RpcServiceMethod(
ModbusGateway_method_names[0],
::grpc::internal::RpcMethod::NORMAL_RPC,
new ::grpc::internal::RpcMethodHandler< ModbusGateway::Service, ::hc900::ReadTagsRequest, ::hc900::ReadTagsResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(
[](ModbusGateway::Service* service,
::grpc::ServerContext* ctx,
const ::hc900::ReadTagsRequest* req,
::hc900::ReadTagsResponse* resp) {
return service->ReadTags(ctx, req, resp);
}, this)));
AddMethod(new ::grpc::internal::RpcServiceMethod(
ModbusGateway_method_names[1],
::grpc::internal::RpcMethod::NORMAL_RPC,
new ::grpc::internal::RpcMethodHandler< ModbusGateway::Service, ::hc900::WriteTagRequest, ::hc900::WriteTagResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(
[](ModbusGateway::Service* service,
::grpc::ServerContext* ctx,
const ::hc900::WriteTagRequest* req,
::hc900::WriteTagResponse* resp) {
return service->WriteTag(ctx, req, resp);
}, this)));
AddMethod(new ::grpc::internal::RpcServiceMethod(
ModbusGateway_method_names[2],
::grpc::internal::RpcMethod::SERVER_STREAMING,
new ::grpc::internal::ServerStreamingHandler< ModbusGateway::Service, ::hc900::StreamTagsRequest, ::hc900::TagValue>(
[](ModbusGateway::Service* service,
::grpc::ServerContext* ctx,
const ::hc900::StreamTagsRequest* req,
::grpc::ServerWriter<::hc900::TagValue>* writer) {
return service->StreamTags(ctx, req, writer);
}, this)));
AddMethod(new ::grpc::internal::RpcServiceMethod(
ModbusGateway_method_names[3],
::grpc::internal::RpcMethod::NORMAL_RPC,
new ::grpc::internal::RpcMethodHandler< ModbusGateway::Service, ::hc900::ListTagsRequest, ::hc900::ListTagsResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(
[](ModbusGateway::Service* service,
::grpc::ServerContext* ctx,
const ::hc900::ListTagsRequest* req,
::hc900::ListTagsResponse* resp) {
return service->ListTags(ctx, req, resp);
}, this)));
AddMethod(new ::grpc::internal::RpcServiceMethod(
ModbusGateway_method_names[4],
::grpc::internal::RpcMethod::NORMAL_RPC,
new ::grpc::internal::RpcMethodHandler< ModbusGateway::Service, ::hc900::HealthCheckRequest, ::hc900::HealthCheckResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(
[](ModbusGateway::Service* service,
::grpc::ServerContext* ctx,
const ::hc900::HealthCheckRequest* req,
::hc900::HealthCheckResponse* resp) {
return service->HealthCheck(ctx, req, resp);
}, this)));
}
ModbusGateway::Service::~Service() {
}
::grpc::Status ModbusGateway::Service::ReadTags(::grpc::ServerContext* context, const ::hc900::ReadTagsRequest* request, ::hc900::ReadTagsResponse* response) {
(void) context;
(void) request;
(void) response;
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
::grpc::Status ModbusGateway::Service::WriteTag(::grpc::ServerContext* context, const ::hc900::WriteTagRequest* request, ::hc900::WriteTagResponse* response) {
(void) context;
(void) request;
(void) response;
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
::grpc::Status ModbusGateway::Service::StreamTags(::grpc::ServerContext* context, const ::hc900::StreamTagsRequest* request, ::grpc::ServerWriter< ::hc900::TagValue>* writer) {
(void) context;
(void) request;
(void) writer;
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
::grpc::Status ModbusGateway::Service::ListTags(::grpc::ServerContext* context, const ::hc900::ListTagsRequest* request, ::hc900::ListTagsResponse* response) {
(void) context;
(void) request;
(void) response;
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
::grpc::Status ModbusGateway::Service::HealthCheck(::grpc::ServerContext* context, const ::hc900::HealthCheckRequest* request, ::hc900::HealthCheckResponse* response) {
(void) context;
(void) request;
(void) response;
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
} // namespace hc900

View File

@@ -0,0 +1,869 @@
// Generated by the gRPC C++ plugin.
// If you make any local change, they will be lost.
// source: modbus_gateway.proto
#ifndef GRPC_modbus_5fgateway_2eproto__INCLUDED
#define GRPC_modbus_5fgateway_2eproto__INCLUDED
#include "modbus_gateway.pb.h"
#include <functional>
#include <grpcpp/generic/async_generic_service.h>
#include <grpcpp/support/async_stream.h>
#include <grpcpp/support/async_unary_call.h>
#include <grpcpp/support/client_callback.h>
#include <grpcpp/client_context.h>
#include <grpcpp/completion_queue.h>
#include <grpcpp/support/message_allocator.h>
#include <grpcpp/support/method_handler.h>
#include <grpcpp/impl/codegen/proto_utils.h>
#include <grpcpp/impl/rpc_method.h>
#include <grpcpp/support/server_callback.h>
#include <grpcpp/impl/codegen/server_callback_handlers.h>
#include <grpcpp/server_context.h>
#include <grpcpp/impl/service_type.h>
#include <grpcpp/impl/codegen/status.h>
#include <grpcpp/support/stub_options.h>
#include <grpcpp/support/sync_stream.h>
namespace hc900 {
// ─── Service ───
//
class ModbusGateway final {
public:
static constexpr char const* service_full_name() {
return "hc900.ModbusGateway";
}
class StubInterface {
public:
virtual ~StubInterface() {}
virtual ::grpc::Status ReadTags(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest& request, ::hc900::ReadTagsResponse* response) = 0;
std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::ReadTagsResponse>> AsyncReadTags(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::ReadTagsResponse>>(AsyncReadTagsRaw(context, request, cq));
}
std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::ReadTagsResponse>> PrepareAsyncReadTags(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::ReadTagsResponse>>(PrepareAsyncReadTagsRaw(context, request, cq));
}
virtual ::grpc::Status WriteTag(::grpc::ClientContext* context, const ::hc900::WriteTagRequest& request, ::hc900::WriteTagResponse* response) = 0;
std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::WriteTagResponse>> AsyncWriteTag(::grpc::ClientContext* context, const ::hc900::WriteTagRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::WriteTagResponse>>(AsyncWriteTagRaw(context, request, cq));
}
std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::WriteTagResponse>> PrepareAsyncWriteTag(::grpc::ClientContext* context, const ::hc900::WriteTagRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::WriteTagResponse>>(PrepareAsyncWriteTagRaw(context, request, cq));
}
std::unique_ptr< ::grpc::ClientReaderInterface< ::hc900::TagValue>> StreamTags(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request) {
return std::unique_ptr< ::grpc::ClientReaderInterface< ::hc900::TagValue>>(StreamTagsRaw(context, request));
}
std::unique_ptr< ::grpc::ClientAsyncReaderInterface< ::hc900::TagValue>> AsyncStreamTags(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncReaderInterface< ::hc900::TagValue>>(AsyncStreamTagsRaw(context, request, cq, tag));
}
std::unique_ptr< ::grpc::ClientAsyncReaderInterface< ::hc900::TagValue>> PrepareAsyncStreamTags(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncReaderInterface< ::hc900::TagValue>>(PrepareAsyncStreamTagsRaw(context, request, cq));
}
virtual ::grpc::Status ListTags(::grpc::ClientContext* context, const ::hc900::ListTagsRequest& request, ::hc900::ListTagsResponse* response) = 0;
std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::ListTagsResponse>> AsyncListTags(::grpc::ClientContext* context, const ::hc900::ListTagsRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::ListTagsResponse>>(AsyncListTagsRaw(context, request, cq));
}
std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::ListTagsResponse>> PrepareAsyncListTags(::grpc::ClientContext* context, const ::hc900::ListTagsRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::ListTagsResponse>>(PrepareAsyncListTagsRaw(context, request, cq));
}
virtual ::grpc::Status HealthCheck(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest& request, ::hc900::HealthCheckResponse* response) = 0;
std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::HealthCheckResponse>> AsyncHealthCheck(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::HealthCheckResponse>>(AsyncHealthCheckRaw(context, request, cq));
}
std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::HealthCheckResponse>> PrepareAsyncHealthCheck(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::hc900::HealthCheckResponse>>(PrepareAsyncHealthCheckRaw(context, request, cq));
}
class async_interface {
public:
virtual ~async_interface() {}
virtual void ReadTags(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest* request, ::hc900::ReadTagsResponse* response, std::function<void(::grpc::Status)>) = 0;
virtual void ReadTags(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest* request, ::hc900::ReadTagsResponse* response, ::grpc::ClientUnaryReactor* reactor) = 0;
virtual void WriteTag(::grpc::ClientContext* context, const ::hc900::WriteTagRequest* request, ::hc900::WriteTagResponse* response, std::function<void(::grpc::Status)>) = 0;
virtual void WriteTag(::grpc::ClientContext* context, const ::hc900::WriteTagRequest* request, ::hc900::WriteTagResponse* response, ::grpc::ClientUnaryReactor* reactor) = 0;
virtual void StreamTags(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest* request, ::grpc::ClientReadReactor< ::hc900::TagValue>* reactor) = 0;
virtual void ListTags(::grpc::ClientContext* context, const ::hc900::ListTagsRequest* request, ::hc900::ListTagsResponse* response, std::function<void(::grpc::Status)>) = 0;
virtual void ListTags(::grpc::ClientContext* context, const ::hc900::ListTagsRequest* request, ::hc900::ListTagsResponse* response, ::grpc::ClientUnaryReactor* reactor) = 0;
virtual void HealthCheck(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest* request, ::hc900::HealthCheckResponse* response, std::function<void(::grpc::Status)>) = 0;
virtual void HealthCheck(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest* request, ::hc900::HealthCheckResponse* response, ::grpc::ClientUnaryReactor* reactor) = 0;
};
typedef class async_interface experimental_async_interface;
virtual class async_interface* async() { return nullptr; }
class async_interface* experimental_async() { return async(); }
private:
virtual ::grpc::ClientAsyncResponseReaderInterface< ::hc900::ReadTagsResponse>* AsyncReadTagsRaw(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientAsyncResponseReaderInterface< ::hc900::ReadTagsResponse>* PrepareAsyncReadTagsRaw(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientAsyncResponseReaderInterface< ::hc900::WriteTagResponse>* AsyncWriteTagRaw(::grpc::ClientContext* context, const ::hc900::WriteTagRequest& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientAsyncResponseReaderInterface< ::hc900::WriteTagResponse>* PrepareAsyncWriteTagRaw(::grpc::ClientContext* context, const ::hc900::WriteTagRequest& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientReaderInterface< ::hc900::TagValue>* StreamTagsRaw(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request) = 0;
virtual ::grpc::ClientAsyncReaderInterface< ::hc900::TagValue>* AsyncStreamTagsRaw(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request, ::grpc::CompletionQueue* cq, void* tag) = 0;
virtual ::grpc::ClientAsyncReaderInterface< ::hc900::TagValue>* PrepareAsyncStreamTagsRaw(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientAsyncResponseReaderInterface< ::hc900::ListTagsResponse>* AsyncListTagsRaw(::grpc::ClientContext* context, const ::hc900::ListTagsRequest& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientAsyncResponseReaderInterface< ::hc900::ListTagsResponse>* PrepareAsyncListTagsRaw(::grpc::ClientContext* context, const ::hc900::ListTagsRequest& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientAsyncResponseReaderInterface< ::hc900::HealthCheckResponse>* AsyncHealthCheckRaw(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientAsyncResponseReaderInterface< ::hc900::HealthCheckResponse>* PrepareAsyncHealthCheckRaw(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest& request, ::grpc::CompletionQueue* cq) = 0;
};
class Stub final : public StubInterface {
public:
Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions());
::grpc::Status ReadTags(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest& request, ::hc900::ReadTagsResponse* response) override;
std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::ReadTagsResponse>> AsyncReadTags(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::ReadTagsResponse>>(AsyncReadTagsRaw(context, request, cq));
}
std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::ReadTagsResponse>> PrepareAsyncReadTags(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::ReadTagsResponse>>(PrepareAsyncReadTagsRaw(context, request, cq));
}
::grpc::Status WriteTag(::grpc::ClientContext* context, const ::hc900::WriteTagRequest& request, ::hc900::WriteTagResponse* response) override;
std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::WriteTagResponse>> AsyncWriteTag(::grpc::ClientContext* context, const ::hc900::WriteTagRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::WriteTagResponse>>(AsyncWriteTagRaw(context, request, cq));
}
std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::WriteTagResponse>> PrepareAsyncWriteTag(::grpc::ClientContext* context, const ::hc900::WriteTagRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::WriteTagResponse>>(PrepareAsyncWriteTagRaw(context, request, cq));
}
std::unique_ptr< ::grpc::ClientReader< ::hc900::TagValue>> StreamTags(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request) {
return std::unique_ptr< ::grpc::ClientReader< ::hc900::TagValue>>(StreamTagsRaw(context, request));
}
std::unique_ptr< ::grpc::ClientAsyncReader< ::hc900::TagValue>> AsyncStreamTags(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncReader< ::hc900::TagValue>>(AsyncStreamTagsRaw(context, request, cq, tag));
}
std::unique_ptr< ::grpc::ClientAsyncReader< ::hc900::TagValue>> PrepareAsyncStreamTags(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncReader< ::hc900::TagValue>>(PrepareAsyncStreamTagsRaw(context, request, cq));
}
::grpc::Status ListTags(::grpc::ClientContext* context, const ::hc900::ListTagsRequest& request, ::hc900::ListTagsResponse* response) override;
std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::ListTagsResponse>> AsyncListTags(::grpc::ClientContext* context, const ::hc900::ListTagsRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::ListTagsResponse>>(AsyncListTagsRaw(context, request, cq));
}
std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::ListTagsResponse>> PrepareAsyncListTags(::grpc::ClientContext* context, const ::hc900::ListTagsRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::ListTagsResponse>>(PrepareAsyncListTagsRaw(context, request, cq));
}
::grpc::Status HealthCheck(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest& request, ::hc900::HealthCheckResponse* response) override;
std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::HealthCheckResponse>> AsyncHealthCheck(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::HealthCheckResponse>>(AsyncHealthCheckRaw(context, request, cq));
}
std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::HealthCheckResponse>> PrepareAsyncHealthCheck(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::hc900::HealthCheckResponse>>(PrepareAsyncHealthCheckRaw(context, request, cq));
}
class async final :
public StubInterface::async_interface {
public:
void ReadTags(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest* request, ::hc900::ReadTagsResponse* response, std::function<void(::grpc::Status)>) override;
void ReadTags(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest* request, ::hc900::ReadTagsResponse* response, ::grpc::ClientUnaryReactor* reactor) override;
void WriteTag(::grpc::ClientContext* context, const ::hc900::WriteTagRequest* request, ::hc900::WriteTagResponse* response, std::function<void(::grpc::Status)>) override;
void WriteTag(::grpc::ClientContext* context, const ::hc900::WriteTagRequest* request, ::hc900::WriteTagResponse* response, ::grpc::ClientUnaryReactor* reactor) override;
void StreamTags(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest* request, ::grpc::ClientReadReactor< ::hc900::TagValue>* reactor) override;
void ListTags(::grpc::ClientContext* context, const ::hc900::ListTagsRequest* request, ::hc900::ListTagsResponse* response, std::function<void(::grpc::Status)>) override;
void ListTags(::grpc::ClientContext* context, const ::hc900::ListTagsRequest* request, ::hc900::ListTagsResponse* response, ::grpc::ClientUnaryReactor* reactor) override;
void HealthCheck(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest* request, ::hc900::HealthCheckResponse* response, std::function<void(::grpc::Status)>) override;
void HealthCheck(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest* request, ::hc900::HealthCheckResponse* response, ::grpc::ClientUnaryReactor* reactor) override;
private:
friend class Stub;
explicit async(Stub* stub): stub_(stub) { }
Stub* stub() { return stub_; }
Stub* stub_;
};
class async* async() override { return &async_stub_; }
private:
std::shared_ptr< ::grpc::ChannelInterface> channel_;
class async async_stub_{this};
::grpc::ClientAsyncResponseReader< ::hc900::ReadTagsResponse>* AsyncReadTagsRaw(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientAsyncResponseReader< ::hc900::ReadTagsResponse>* PrepareAsyncReadTagsRaw(::grpc::ClientContext* context, const ::hc900::ReadTagsRequest& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientAsyncResponseReader< ::hc900::WriteTagResponse>* AsyncWriteTagRaw(::grpc::ClientContext* context, const ::hc900::WriteTagRequest& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientAsyncResponseReader< ::hc900::WriteTagResponse>* PrepareAsyncWriteTagRaw(::grpc::ClientContext* context, const ::hc900::WriteTagRequest& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientReader< ::hc900::TagValue>* StreamTagsRaw(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request) override;
::grpc::ClientAsyncReader< ::hc900::TagValue>* AsyncStreamTagsRaw(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request, ::grpc::CompletionQueue* cq, void* tag) override;
::grpc::ClientAsyncReader< ::hc900::TagValue>* PrepareAsyncStreamTagsRaw(::grpc::ClientContext* context, const ::hc900::StreamTagsRequest& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientAsyncResponseReader< ::hc900::ListTagsResponse>* AsyncListTagsRaw(::grpc::ClientContext* context, const ::hc900::ListTagsRequest& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientAsyncResponseReader< ::hc900::ListTagsResponse>* PrepareAsyncListTagsRaw(::grpc::ClientContext* context, const ::hc900::ListTagsRequest& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientAsyncResponseReader< ::hc900::HealthCheckResponse>* AsyncHealthCheckRaw(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest& request, ::grpc::CompletionQueue* cq) override;
::grpc::ClientAsyncResponseReader< ::hc900::HealthCheckResponse>* PrepareAsyncHealthCheckRaw(::grpc::ClientContext* context, const ::hc900::HealthCheckRequest& request, ::grpc::CompletionQueue* cq) override;
const ::grpc::internal::RpcMethod rpcmethod_ReadTags_;
const ::grpc::internal::RpcMethod rpcmethod_WriteTag_;
const ::grpc::internal::RpcMethod rpcmethod_StreamTags_;
const ::grpc::internal::RpcMethod rpcmethod_ListTags_;
const ::grpc::internal::RpcMethod rpcmethod_HealthCheck_;
};
static std::unique_ptr<Stub> NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions());
class Service : public ::grpc::Service {
public:
Service();
virtual ~Service();
virtual ::grpc::Status ReadTags(::grpc::ServerContext* context, const ::hc900::ReadTagsRequest* request, ::hc900::ReadTagsResponse* response);
virtual ::grpc::Status WriteTag(::grpc::ServerContext* context, const ::hc900::WriteTagRequest* request, ::hc900::WriteTagResponse* response);
virtual ::grpc::Status StreamTags(::grpc::ServerContext* context, const ::hc900::StreamTagsRequest* request, ::grpc::ServerWriter< ::hc900::TagValue>* writer);
virtual ::grpc::Status ListTags(::grpc::ServerContext* context, const ::hc900::ListTagsRequest* request, ::hc900::ListTagsResponse* response);
virtual ::grpc::Status HealthCheck(::grpc::ServerContext* context, const ::hc900::HealthCheckRequest* request, ::hc900::HealthCheckResponse* response);
};
template <class BaseClass>
class WithAsyncMethod_ReadTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithAsyncMethod_ReadTags() {
::grpc::Service::MarkMethodAsync(0);
}
~WithAsyncMethod_ReadTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status ReadTags(::grpc::ServerContext* /*context*/, const ::hc900::ReadTagsRequest* /*request*/, ::hc900::ReadTagsResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestReadTags(::grpc::ServerContext* context, ::hc900::ReadTagsRequest* request, ::grpc::ServerAsyncResponseWriter< ::hc900::ReadTagsResponse>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag);
}
};
template <class BaseClass>
class WithAsyncMethod_WriteTag : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithAsyncMethod_WriteTag() {
::grpc::Service::MarkMethodAsync(1);
}
~WithAsyncMethod_WriteTag() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status WriteTag(::grpc::ServerContext* /*context*/, const ::hc900::WriteTagRequest* /*request*/, ::hc900::WriteTagResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestWriteTag(::grpc::ServerContext* context, ::hc900::WriteTagRequest* request, ::grpc::ServerAsyncResponseWriter< ::hc900::WriteTagResponse>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncUnary(1, context, request, response, new_call_cq, notification_cq, tag);
}
};
template <class BaseClass>
class WithAsyncMethod_StreamTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithAsyncMethod_StreamTags() {
::grpc::Service::MarkMethodAsync(2);
}
~WithAsyncMethod_StreamTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status StreamTags(::grpc::ServerContext* /*context*/, const ::hc900::StreamTagsRequest* /*request*/, ::grpc::ServerWriter< ::hc900::TagValue>* /*writer*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestStreamTags(::grpc::ServerContext* context, ::hc900::StreamTagsRequest* request, ::grpc::ServerAsyncWriter< ::hc900::TagValue>* writer, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncServerStreaming(2, context, request, writer, new_call_cq, notification_cq, tag);
}
};
template <class BaseClass>
class WithAsyncMethod_ListTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithAsyncMethod_ListTags() {
::grpc::Service::MarkMethodAsync(3);
}
~WithAsyncMethod_ListTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status ListTags(::grpc::ServerContext* /*context*/, const ::hc900::ListTagsRequest* /*request*/, ::hc900::ListTagsResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestListTags(::grpc::ServerContext* context, ::hc900::ListTagsRequest* request, ::grpc::ServerAsyncResponseWriter< ::hc900::ListTagsResponse>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncUnary(3, context, request, response, new_call_cq, notification_cq, tag);
}
};
template <class BaseClass>
class WithAsyncMethod_HealthCheck : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithAsyncMethod_HealthCheck() {
::grpc::Service::MarkMethodAsync(4);
}
~WithAsyncMethod_HealthCheck() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status HealthCheck(::grpc::ServerContext* /*context*/, const ::hc900::HealthCheckRequest* /*request*/, ::hc900::HealthCheckResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestHealthCheck(::grpc::ServerContext* context, ::hc900::HealthCheckRequest* request, ::grpc::ServerAsyncResponseWriter< ::hc900::HealthCheckResponse>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncUnary(4, context, request, response, new_call_cq, notification_cq, tag);
}
};
typedef WithAsyncMethod_ReadTags<WithAsyncMethod_WriteTag<WithAsyncMethod_StreamTags<WithAsyncMethod_ListTags<WithAsyncMethod_HealthCheck<Service > > > > > AsyncService;
template <class BaseClass>
class WithCallbackMethod_ReadTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithCallbackMethod_ReadTags() {
::grpc::Service::MarkMethodCallback(0,
new ::grpc::internal::CallbackUnaryHandler< ::hc900::ReadTagsRequest, ::hc900::ReadTagsResponse>(
[this](
::grpc::CallbackServerContext* context, const ::hc900::ReadTagsRequest* request, ::hc900::ReadTagsResponse* response) { return this->ReadTags(context, request, response); }));}
void SetMessageAllocatorFor_ReadTags(
::grpc::MessageAllocator< ::hc900::ReadTagsRequest, ::hc900::ReadTagsResponse>* allocator) {
::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(0);
static_cast<::grpc::internal::CallbackUnaryHandler< ::hc900::ReadTagsRequest, ::hc900::ReadTagsResponse>*>(handler)
->SetMessageAllocator(allocator);
}
~WithCallbackMethod_ReadTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status ReadTags(::grpc::ServerContext* /*context*/, const ::hc900::ReadTagsRequest* /*request*/, ::hc900::ReadTagsResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::ServerUnaryReactor* ReadTags(
::grpc::CallbackServerContext* /*context*/, const ::hc900::ReadTagsRequest* /*request*/, ::hc900::ReadTagsResponse* /*response*/) { return nullptr; }
};
template <class BaseClass>
class WithCallbackMethod_WriteTag : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithCallbackMethod_WriteTag() {
::grpc::Service::MarkMethodCallback(1,
new ::grpc::internal::CallbackUnaryHandler< ::hc900::WriteTagRequest, ::hc900::WriteTagResponse>(
[this](
::grpc::CallbackServerContext* context, const ::hc900::WriteTagRequest* request, ::hc900::WriteTagResponse* response) { return this->WriteTag(context, request, response); }));}
void SetMessageAllocatorFor_WriteTag(
::grpc::MessageAllocator< ::hc900::WriteTagRequest, ::hc900::WriteTagResponse>* allocator) {
::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(1);
static_cast<::grpc::internal::CallbackUnaryHandler< ::hc900::WriteTagRequest, ::hc900::WriteTagResponse>*>(handler)
->SetMessageAllocator(allocator);
}
~WithCallbackMethod_WriteTag() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status WriteTag(::grpc::ServerContext* /*context*/, const ::hc900::WriteTagRequest* /*request*/, ::hc900::WriteTagResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::ServerUnaryReactor* WriteTag(
::grpc::CallbackServerContext* /*context*/, const ::hc900::WriteTagRequest* /*request*/, ::hc900::WriteTagResponse* /*response*/) { return nullptr; }
};
template <class BaseClass>
class WithCallbackMethod_StreamTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithCallbackMethod_StreamTags() {
::grpc::Service::MarkMethodCallback(2,
new ::grpc::internal::CallbackServerStreamingHandler< ::hc900::StreamTagsRequest, ::hc900::TagValue>(
[this](
::grpc::CallbackServerContext* context, const ::hc900::StreamTagsRequest* request) { return this->StreamTags(context, request); }));
}
~WithCallbackMethod_StreamTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status StreamTags(::grpc::ServerContext* /*context*/, const ::hc900::StreamTagsRequest* /*request*/, ::grpc::ServerWriter< ::hc900::TagValue>* /*writer*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::ServerWriteReactor< ::hc900::TagValue>* StreamTags(
::grpc::CallbackServerContext* /*context*/, const ::hc900::StreamTagsRequest* /*request*/) { return nullptr; }
};
template <class BaseClass>
class WithCallbackMethod_ListTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithCallbackMethod_ListTags() {
::grpc::Service::MarkMethodCallback(3,
new ::grpc::internal::CallbackUnaryHandler< ::hc900::ListTagsRequest, ::hc900::ListTagsResponse>(
[this](
::grpc::CallbackServerContext* context, const ::hc900::ListTagsRequest* request, ::hc900::ListTagsResponse* response) { return this->ListTags(context, request, response); }));}
void SetMessageAllocatorFor_ListTags(
::grpc::MessageAllocator< ::hc900::ListTagsRequest, ::hc900::ListTagsResponse>* allocator) {
::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(3);
static_cast<::grpc::internal::CallbackUnaryHandler< ::hc900::ListTagsRequest, ::hc900::ListTagsResponse>*>(handler)
->SetMessageAllocator(allocator);
}
~WithCallbackMethod_ListTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status ListTags(::grpc::ServerContext* /*context*/, const ::hc900::ListTagsRequest* /*request*/, ::hc900::ListTagsResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::ServerUnaryReactor* ListTags(
::grpc::CallbackServerContext* /*context*/, const ::hc900::ListTagsRequest* /*request*/, ::hc900::ListTagsResponse* /*response*/) { return nullptr; }
};
template <class BaseClass>
class WithCallbackMethod_HealthCheck : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithCallbackMethod_HealthCheck() {
::grpc::Service::MarkMethodCallback(4,
new ::grpc::internal::CallbackUnaryHandler< ::hc900::HealthCheckRequest, ::hc900::HealthCheckResponse>(
[this](
::grpc::CallbackServerContext* context, const ::hc900::HealthCheckRequest* request, ::hc900::HealthCheckResponse* response) { return this->HealthCheck(context, request, response); }));}
void SetMessageAllocatorFor_HealthCheck(
::grpc::MessageAllocator< ::hc900::HealthCheckRequest, ::hc900::HealthCheckResponse>* allocator) {
::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(4);
static_cast<::grpc::internal::CallbackUnaryHandler< ::hc900::HealthCheckRequest, ::hc900::HealthCheckResponse>*>(handler)
->SetMessageAllocator(allocator);
}
~WithCallbackMethod_HealthCheck() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status HealthCheck(::grpc::ServerContext* /*context*/, const ::hc900::HealthCheckRequest* /*request*/, ::hc900::HealthCheckResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::ServerUnaryReactor* HealthCheck(
::grpc::CallbackServerContext* /*context*/, const ::hc900::HealthCheckRequest* /*request*/, ::hc900::HealthCheckResponse* /*response*/) { return nullptr; }
};
typedef WithCallbackMethod_ReadTags<WithCallbackMethod_WriteTag<WithCallbackMethod_StreamTags<WithCallbackMethod_ListTags<WithCallbackMethod_HealthCheck<Service > > > > > CallbackService;
typedef CallbackService ExperimentalCallbackService;
template <class BaseClass>
class WithGenericMethod_ReadTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithGenericMethod_ReadTags() {
::grpc::Service::MarkMethodGeneric(0);
}
~WithGenericMethod_ReadTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status ReadTags(::grpc::ServerContext* /*context*/, const ::hc900::ReadTagsRequest* /*request*/, ::hc900::ReadTagsResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
};
template <class BaseClass>
class WithGenericMethod_WriteTag : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithGenericMethod_WriteTag() {
::grpc::Service::MarkMethodGeneric(1);
}
~WithGenericMethod_WriteTag() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status WriteTag(::grpc::ServerContext* /*context*/, const ::hc900::WriteTagRequest* /*request*/, ::hc900::WriteTagResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
};
template <class BaseClass>
class WithGenericMethod_StreamTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithGenericMethod_StreamTags() {
::grpc::Service::MarkMethodGeneric(2);
}
~WithGenericMethod_StreamTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status StreamTags(::grpc::ServerContext* /*context*/, const ::hc900::StreamTagsRequest* /*request*/, ::grpc::ServerWriter< ::hc900::TagValue>* /*writer*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
};
template <class BaseClass>
class WithGenericMethod_ListTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithGenericMethod_ListTags() {
::grpc::Service::MarkMethodGeneric(3);
}
~WithGenericMethod_ListTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status ListTags(::grpc::ServerContext* /*context*/, const ::hc900::ListTagsRequest* /*request*/, ::hc900::ListTagsResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
};
template <class BaseClass>
class WithGenericMethod_HealthCheck : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithGenericMethod_HealthCheck() {
::grpc::Service::MarkMethodGeneric(4);
}
~WithGenericMethod_HealthCheck() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status HealthCheck(::grpc::ServerContext* /*context*/, const ::hc900::HealthCheckRequest* /*request*/, ::hc900::HealthCheckResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
};
template <class BaseClass>
class WithRawMethod_ReadTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithRawMethod_ReadTags() {
::grpc::Service::MarkMethodRaw(0);
}
~WithRawMethod_ReadTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status ReadTags(::grpc::ServerContext* /*context*/, const ::hc900::ReadTagsRequest* /*request*/, ::hc900::ReadTagsResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestReadTags(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag);
}
};
template <class BaseClass>
class WithRawMethod_WriteTag : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithRawMethod_WriteTag() {
::grpc::Service::MarkMethodRaw(1);
}
~WithRawMethod_WriteTag() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status WriteTag(::grpc::ServerContext* /*context*/, const ::hc900::WriteTagRequest* /*request*/, ::hc900::WriteTagResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestWriteTag(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncUnary(1, context, request, response, new_call_cq, notification_cq, tag);
}
};
template <class BaseClass>
class WithRawMethod_StreamTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithRawMethod_StreamTags() {
::grpc::Service::MarkMethodRaw(2);
}
~WithRawMethod_StreamTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status StreamTags(::grpc::ServerContext* /*context*/, const ::hc900::StreamTagsRequest* /*request*/, ::grpc::ServerWriter< ::hc900::TagValue>* /*writer*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestStreamTags(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncWriter< ::grpc::ByteBuffer>* writer, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncServerStreaming(2, context, request, writer, new_call_cq, notification_cq, tag);
}
};
template <class BaseClass>
class WithRawMethod_ListTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithRawMethod_ListTags() {
::grpc::Service::MarkMethodRaw(3);
}
~WithRawMethod_ListTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status ListTags(::grpc::ServerContext* /*context*/, const ::hc900::ListTagsRequest* /*request*/, ::hc900::ListTagsResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestListTags(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncUnary(3, context, request, response, new_call_cq, notification_cq, tag);
}
};
template <class BaseClass>
class WithRawMethod_HealthCheck : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithRawMethod_HealthCheck() {
::grpc::Service::MarkMethodRaw(4);
}
~WithRawMethod_HealthCheck() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status HealthCheck(::grpc::ServerContext* /*context*/, const ::hc900::HealthCheckRequest* /*request*/, ::hc900::HealthCheckResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestHealthCheck(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncUnary(4, context, request, response, new_call_cq, notification_cq, tag);
}
};
template <class BaseClass>
class WithRawCallbackMethod_ReadTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithRawCallbackMethod_ReadTags() {
::grpc::Service::MarkMethodRawCallback(0,
new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
[this](
::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->ReadTags(context, request, response); }));
}
~WithRawCallbackMethod_ReadTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status ReadTags(::grpc::ServerContext* /*context*/, const ::hc900::ReadTagsRequest* /*request*/, ::hc900::ReadTagsResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::ServerUnaryReactor* ReadTags(
::grpc::CallbackServerContext* /*context*/, const ::grpc::ByteBuffer* /*request*/, ::grpc::ByteBuffer* /*response*/) { return nullptr; }
};
template <class BaseClass>
class WithRawCallbackMethod_WriteTag : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithRawCallbackMethod_WriteTag() {
::grpc::Service::MarkMethodRawCallback(1,
new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
[this](
::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->WriteTag(context, request, response); }));
}
~WithRawCallbackMethod_WriteTag() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status WriteTag(::grpc::ServerContext* /*context*/, const ::hc900::WriteTagRequest* /*request*/, ::hc900::WriteTagResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::ServerUnaryReactor* WriteTag(
::grpc::CallbackServerContext* /*context*/, const ::grpc::ByteBuffer* /*request*/, ::grpc::ByteBuffer* /*response*/) { return nullptr; }
};
template <class BaseClass>
class WithRawCallbackMethod_StreamTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithRawCallbackMethod_StreamTags() {
::grpc::Service::MarkMethodRawCallback(2,
new ::grpc::internal::CallbackServerStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
[this](
::grpc::CallbackServerContext* context, const::grpc::ByteBuffer* request) { return this->StreamTags(context, request); }));
}
~WithRawCallbackMethod_StreamTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status StreamTags(::grpc::ServerContext* /*context*/, const ::hc900::StreamTagsRequest* /*request*/, ::grpc::ServerWriter< ::hc900::TagValue>* /*writer*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::ServerWriteReactor< ::grpc::ByteBuffer>* StreamTags(
::grpc::CallbackServerContext* /*context*/, const ::grpc::ByteBuffer* /*request*/) { return nullptr; }
};
template <class BaseClass>
class WithRawCallbackMethod_ListTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithRawCallbackMethod_ListTags() {
::grpc::Service::MarkMethodRawCallback(3,
new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
[this](
::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->ListTags(context, request, response); }));
}
~WithRawCallbackMethod_ListTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status ListTags(::grpc::ServerContext* /*context*/, const ::hc900::ListTagsRequest* /*request*/, ::hc900::ListTagsResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::ServerUnaryReactor* ListTags(
::grpc::CallbackServerContext* /*context*/, const ::grpc::ByteBuffer* /*request*/, ::grpc::ByteBuffer* /*response*/) { return nullptr; }
};
template <class BaseClass>
class WithRawCallbackMethod_HealthCheck : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithRawCallbackMethod_HealthCheck() {
::grpc::Service::MarkMethodRawCallback(4,
new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>(
[this](
::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->HealthCheck(context, request, response); }));
}
~WithRawCallbackMethod_HealthCheck() override {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status HealthCheck(::grpc::ServerContext* /*context*/, const ::hc900::HealthCheckRequest* /*request*/, ::hc900::HealthCheckResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
virtual ::grpc::ServerUnaryReactor* HealthCheck(
::grpc::CallbackServerContext* /*context*/, const ::grpc::ByteBuffer* /*request*/, ::grpc::ByteBuffer* /*response*/) { return nullptr; }
};
template <class BaseClass>
class WithStreamedUnaryMethod_ReadTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithStreamedUnaryMethod_ReadTags() {
::grpc::Service::MarkMethodStreamed(0,
new ::grpc::internal::StreamedUnaryHandler<
::hc900::ReadTagsRequest, ::hc900::ReadTagsResponse>(
[this](::grpc::ServerContext* context,
::grpc::ServerUnaryStreamer<
::hc900::ReadTagsRequest, ::hc900::ReadTagsResponse>* streamer) {
return this->StreamedReadTags(context,
streamer);
}));
}
~WithStreamedUnaryMethod_ReadTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable regular version of this method
::grpc::Status ReadTags(::grpc::ServerContext* /*context*/, const ::hc900::ReadTagsRequest* /*request*/, ::hc900::ReadTagsResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
// replace default version of method with streamed unary
virtual ::grpc::Status StreamedReadTags(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::hc900::ReadTagsRequest,::hc900::ReadTagsResponse>* server_unary_streamer) = 0;
};
template <class BaseClass>
class WithStreamedUnaryMethod_WriteTag : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithStreamedUnaryMethod_WriteTag() {
::grpc::Service::MarkMethodStreamed(1,
new ::grpc::internal::StreamedUnaryHandler<
::hc900::WriteTagRequest, ::hc900::WriteTagResponse>(
[this](::grpc::ServerContext* context,
::grpc::ServerUnaryStreamer<
::hc900::WriteTagRequest, ::hc900::WriteTagResponse>* streamer) {
return this->StreamedWriteTag(context,
streamer);
}));
}
~WithStreamedUnaryMethod_WriteTag() override {
BaseClassMustBeDerivedFromService(this);
}
// disable regular version of this method
::grpc::Status WriteTag(::grpc::ServerContext* /*context*/, const ::hc900::WriteTagRequest* /*request*/, ::hc900::WriteTagResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
// replace default version of method with streamed unary
virtual ::grpc::Status StreamedWriteTag(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::hc900::WriteTagRequest,::hc900::WriteTagResponse>* server_unary_streamer) = 0;
};
template <class BaseClass>
class WithStreamedUnaryMethod_ListTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithStreamedUnaryMethod_ListTags() {
::grpc::Service::MarkMethodStreamed(3,
new ::grpc::internal::StreamedUnaryHandler<
::hc900::ListTagsRequest, ::hc900::ListTagsResponse>(
[this](::grpc::ServerContext* context,
::grpc::ServerUnaryStreamer<
::hc900::ListTagsRequest, ::hc900::ListTagsResponse>* streamer) {
return this->StreamedListTags(context,
streamer);
}));
}
~WithStreamedUnaryMethod_ListTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable regular version of this method
::grpc::Status ListTags(::grpc::ServerContext* /*context*/, const ::hc900::ListTagsRequest* /*request*/, ::hc900::ListTagsResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
// replace default version of method with streamed unary
virtual ::grpc::Status StreamedListTags(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::hc900::ListTagsRequest,::hc900::ListTagsResponse>* server_unary_streamer) = 0;
};
template <class BaseClass>
class WithStreamedUnaryMethod_HealthCheck : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithStreamedUnaryMethod_HealthCheck() {
::grpc::Service::MarkMethodStreamed(4,
new ::grpc::internal::StreamedUnaryHandler<
::hc900::HealthCheckRequest, ::hc900::HealthCheckResponse>(
[this](::grpc::ServerContext* context,
::grpc::ServerUnaryStreamer<
::hc900::HealthCheckRequest, ::hc900::HealthCheckResponse>* streamer) {
return this->StreamedHealthCheck(context,
streamer);
}));
}
~WithStreamedUnaryMethod_HealthCheck() override {
BaseClassMustBeDerivedFromService(this);
}
// disable regular version of this method
::grpc::Status HealthCheck(::grpc::ServerContext* /*context*/, const ::hc900::HealthCheckRequest* /*request*/, ::hc900::HealthCheckResponse* /*response*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
// replace default version of method with streamed unary
virtual ::grpc::Status StreamedHealthCheck(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::hc900::HealthCheckRequest,::hc900::HealthCheckResponse>* server_unary_streamer) = 0;
};
typedef WithStreamedUnaryMethod_ReadTags<WithStreamedUnaryMethod_WriteTag<WithStreamedUnaryMethod_ListTags<WithStreamedUnaryMethod_HealthCheck<Service > > > > StreamedUnaryService;
template <class BaseClass>
class WithSplitStreamingMethod_StreamTags : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service* /*service*/) {}
public:
WithSplitStreamingMethod_StreamTags() {
::grpc::Service::MarkMethodStreamed(2,
new ::grpc::internal::SplitServerStreamingHandler<
::hc900::StreamTagsRequest, ::hc900::TagValue>(
[this](::grpc::ServerContext* context,
::grpc::ServerSplitStreamer<
::hc900::StreamTagsRequest, ::hc900::TagValue>* streamer) {
return this->StreamedStreamTags(context,
streamer);
}));
}
~WithSplitStreamingMethod_StreamTags() override {
BaseClassMustBeDerivedFromService(this);
}
// disable regular version of this method
::grpc::Status StreamTags(::grpc::ServerContext* /*context*/, const ::hc900::StreamTagsRequest* /*request*/, ::grpc::ServerWriter< ::hc900::TagValue>* /*writer*/) override {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
// replace default version of method with split streamed
virtual ::grpc::Status StreamedStreamTags(::grpc::ServerContext* context, ::grpc::ServerSplitStreamer< ::hc900::StreamTagsRequest,::hc900::TagValue>* server_split_streamer) = 0;
};
typedef WithSplitStreamingMethod_StreamTags<Service > SplitStreamedService;
typedef WithStreamedUnaryMethod_ReadTags<WithStreamedUnaryMethod_WriteTag<WithSplitStreamingMethod_StreamTags<WithStreamedUnaryMethod_ListTags<WithStreamedUnaryMethod_HealthCheck<Service > > > > > StreamedService;
};
} // namespace hc900
#endif // GRPC_modbus_5fgateway_2eproto__INCLUDED

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
#pragma once
#include <memory>
class Controller;
std::unique_ptr<Controller> init_system();

View File

@@ -0,0 +1,76 @@
#pragma once
#include <array>
#include <cstdint>
#include "data_format.hpp"
//
// ============================================================
// 32-bit (float / int32 / uint32)
// ============================================================
// float (IEEE-754, Modbus 2 registers)
std::array<std::uint16_t, 2>
encode_float(float value, const DataFormat& fmt);
float
decode_float(std::uint16_t r0,
std::uint16_t r1,
const DataFormat& fmt);
// signed 32-bit
std::array<std::uint16_t, 2>
encode_int32(std::int32_t value, const DataFormat& fmt);
std::int32_t
decode_int32(std::uint16_t r0,
std::uint16_t r1,
const DataFormat& fmt);
// unsigned 32-bit
std::array<std::uint16_t, 2>
encode_uint32(std::uint32_t value, const DataFormat& fmt);
std::uint32_t
decode_uint32(std::uint16_t r0,
std::uint16_t r1,
const DataFormat& fmt);
//
// ============================================================
// 64-bit (double / int64 / uint64)
// ============================================================
// double (IEEE-754, Modbus 4 registers)
std::array<std::uint16_t, 4>
encode_double(double value, const DataFormat& fmt);
double
decode_double(std::uint16_t r0,
std::uint16_t r1,
std::uint16_t r2,
std::uint16_t r3,
const DataFormat& fmt);
// signed 64-bit
std::array<std::uint16_t, 4>
encode_int64(std::int64_t value, const DataFormat& fmt);
std::int64_t
decode_int64(std::uint16_t r0,
std::uint16_t r1,
std::uint16_t r2,
std::uint16_t r3,
const DataFormat& fmt);
// unsigned 64-bit
std::array<std::uint16_t, 4>
encode_uint64(std::uint64_t value, const DataFormat& fmt);
std::uint64_t
decode_uint64(std::uint16_t r0,
std::uint16_t r1,
std::uint16_t r2,
std::uint16_t r3,
const DataFormat& fmt);

View File

@@ -0,0 +1,47 @@
#pragma once
#include <cstdint>
#include <memory>
#include <vector>
#include "itransport.hpp"
#include "data_format.hpp"
class Controller {
public:
explicit Controller(std::unique_ptr<ITransport> transport);
// lifecycle
void poll();
bool connect(const char* host, std::uint16_t port);
void disconnect();
bool is_connected() const;
// raw register
bool read_register(std::uint16_t addr, std::uint16_t& value);
bool write_register(std::uint16_t addr, std::uint16_t value);
bool read_raw(std::uint16_t addr, std::uint16_t count, std::vector<std::uint16_t>& out);
// 32-bit
bool read_int32(std::uint16_t addr, std::int32_t& value, const DataFormat& fmt);
bool write_int32(std::uint16_t addr, std::int32_t value, const DataFormat& fmt);
bool read_uint32(std::uint16_t addr, std::uint32_t& value, const DataFormat& fmt);
bool write_uint32(std::uint16_t addr, std::uint32_t value, const DataFormat& fmt);
// float / double
bool read_float(std::uint16_t addr, float& value, const DataFormat& fmt);
bool write_float(std::uint16_t addr, float value, const DataFormat& fmt);
bool read_double(std::uint16_t addr, double& value, const DataFormat& fmt);
bool write_double(std::uint16_t addr, double value, const DataFormat& fmt);
// 64-bit
bool read_int64(std::uint16_t addr, std::int64_t& value, const DataFormat& fmt);
bool write_int64(std::uint16_t addr, std::int64_t value, const DataFormat& fmt);
bool read_uint64(std::uint16_t addr, std::uint64_t& value, const DataFormat& fmt);
bool write_uint64(std::uint16_t addr, std::uint64_t value, const DataFormat& fmt);
private:
std::unique_ptr<ITransport> transport_;
};

View File

@@ -0,0 +1,27 @@
#pragma once
#include <cstdint>
// Byte order inside a 16-bit Modbus register
enum class ByteOrder {
BigEndian, // AB
LittleEndian // BA
};
// Order of 16-bit registers
enum class WordOrder {
HighFirst, // Reg[N] = high word
LowFirst // Reg[N] = low word
};
// Order of register groups (for 64-bit+ types)
enum class RegisterOrder {
Normal, // ABCD EFGH
Swapped // EFGH ABCD
};
struct DataFormat {
ByteOrder byte_order;
WordOrder word_order;
RegisterOrder register_order;
};

View File

@@ -0,0 +1,103 @@
#ifndef HC900_GATEWAY_H
#define HC900_GATEWAY_H
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <atomic>
#include <thread>
#include <mutex>
#include <chrono>
#include "modbus_gateway.grpc.pb.h"
#include "modbus_gateway.pb.h"
class Controller;
struct RegisterEntry {
std::string tag;
uint32_t addr;
uint32_t count; // register count (1 or 2)
std::string type; // "float32" or "uint16"
std::string access; // "R" or "RW"
};
struct CachedValue {
float float32_val;
uint32_t uint16_val;
bool is_float;
uint32_t quality; // 192=good, 0=bad
std::chrono::system_clock::time_point timestamp;
};
class Hc900Gateway final {
public:
Hc900Gateway(const std::string& host, uint16_t port,
const std::string& map_path,
int poll_interval_ms = 1000,
int grpc_port = 50051);
~Hc900Gateway();
bool Start();
void Stop();
private:
void PollLoop();
void LoadRegisterMap(const std::string& path);
void ReadAllRegisters();
CachedValue ReadRegister(const RegisterEntry& entry);
// gRPC service implementation
class GatewayServiceImpl final : public hc900::ModbusGateway::Service {
public:
GatewayServiceImpl(Hc900Gateway& gateway);
grpc::Status ReadTags(grpc::ServerContext* ctx,
const hc900::ReadTagsRequest* req,
hc900::ReadTagsResponse* resp) override;
grpc::Status WriteTag(grpc::ServerContext* ctx,
const hc900::WriteTagRequest* req,
hc900::WriteTagResponse* resp) override;
grpc::Status ListTags(grpc::ServerContext* ctx,
const hc900::ListTagsRequest* req,
hc900::ListTagsResponse* resp) override;
grpc::Status HealthCheck(grpc::ServerContext* ctx,
const hc900::HealthCheckRequest* req,
hc900::HealthCheckResponse* resp) override;
grpc::Status StreamTags(grpc::ServerContext* ctx,
const hc900::StreamTagsRequest* req,
grpc::ServerWriter<hc900::TagValue>* writer) override;
private:
Hc900Gateway& gateway_;
};
std::string host_;
uint16_t port_;
int poll_interval_ms_;
std::unique_ptr<Controller> controller_;
// Register map
std::vector<RegisterEntry> registers_;
std::unordered_map<std::string, size_t> tag_index_;
std::vector<size_t> sorted_indices_; // indices into registers_, sorted by address
// Cache
std::unordered_map<std::string, CachedValue> cache_;
mutable std::mutex cache_mutex_;
// Transport — shared between poll thread and gRPC handlers
mutable std::mutex transport_mutex_;
// Poller
std::atomic<bool> running_;
std::thread poll_thread_;
uint64_t poll_count_{0};
std::chrono::milliseconds last_poll_duration_{0};
// gRPC server
std::unique_ptr<grpc::Server> grpc_server_;
std::unique_ptr<GatewayServiceImpl> grpc_service_;
std::string grpc_listen_;
};
#endif // HC900_GATEWAY_H

View File

@@ -0,0 +1,47 @@
// ITransport 인터페이스 (🔥 최종본)
// itransport.hpp
#pragma once
#include <cstdint>
#include <vector>
#include "transport_error.hpp"
// transport 상태관리
enum class TransportState {
Disconnected,
Connecting,
Connected,
Reconnecting,
Fault,
};
class ITransport {
public:
virtual ~ITransport() = default;
// connection
virtual bool connect(const char* host, std::uint16_t port) = 0;
virtual void disconnect() = 0;
virtual bool is_connected() const = 0;
// state & error handling
virtual TransportState state() const = 0;
virtual TransportError last_error() const = 0;
// io policy
virtual bool can_io() const = 0; // ⭐ 추가 (권장)
// watchdog / reconnect / state machine
virtual void poll() = 0;
virtual void reset() = 0; // ⭐ 추가
// register access
virtual bool read_registers(std::uint16_t addr,
std::uint16_t count,
std::vector<std::uint16_t>& out) = 0;
virtual bool write_registers(std::uint16_t addr,
const std::vector<std::uint16_t>& values) = 0;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
#pragma once
#include "logger.hpp"
// 빌드 옵션으로 제어
#ifndef ENABLE_DEBUG_LOG
#define ENABLE_DEBUG_LOG 0
#endif
#define LOG_INFO(msg) Logger::instance().log("INFO", msg)
#define LOG_WARN(msg) Logger::instance().log("WARN", msg)
#define LOG_ERROR(msg) Logger::instance().log("ERROR", msg)
#define LOG_DEBUG(msg) Logger::instance().log("DEBUG", msg)

View File

@@ -0,0 +1,53 @@
#pragma once
#include <fstream>
#include <mutex>
#include <string>
#include <chrono>
#include <iomanip>
#include <sstream>
class Logger {
public:
static Logger& instance() {
static Logger inst;
return inst;
}
void set_file(const std::string& path) {
std::lock_guard<std::mutex> lock(mutex_);
if (ofs_.is_open())
ofs_.close();
ofs_.open(path, std::ios::out | std::ios::app);
}
void log(const char* level, const std::string& msg) {
std::lock_guard<std::mutex> lock(mutex_);
if (!ofs_.is_open())
return;
ofs_ << timestamp()
<< " [" << level << "] "
<< msg << "\n";
ofs_.flush();
}
private:
Logger() = default;
std::string timestamp() {
using namespace std::chrono;
auto now = system_clock::now();
auto t = system_clock::to_time_t(now);
std::tm tm{};
localtime_r(&t, &tm);
std::ostringstream oss;
oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
return oss.str();
}
std::ofstream ofs_;
std::mutex mutex_;
};

View File

@@ -0,0 +1,16 @@
#pragma once
#include <cstdint>
enum class ModbusException : std::uint8_t {
IllegalFunction = 0x01,
IllegalDataAddress = 0x02,
IllegalDataValue = 0x03,
SlaveDeviceFailure = 0x04,
Acknowledge = 0x05, // ★ 중요
SlaveDeviceBusy = 0x06, // ★ 중요
MemoryParityError = 0x08,
GatewayPathUnavailable = 0x0A,
GatewayTargetFailed = 0x0B
};

View File

@@ -0,0 +1,61 @@
#pragma once
#include "modbus_exception.hpp"
#include "itransport.hpp"
#include "transport_error.hpp"
#include <cstdint>
#include <vector>
#include <chrono>
#include <string>
class ModbusTCP : public ITransport {
public:
ModbusTCP();
~ModbusTCP() override;
bool connect(const char* host, std::uint16_t port) override;
void disconnect() override;
bool is_connected() const override;
TransportState state() const override { return state_; }
TransportError last_error() const override { return last_error_; }
bool read_registers(std::uint16_t addr,
std::uint16_t count,
std::vector<std::uint16_t>& out) override;
bool write_registers(std::uint16_t addr,
const std::vector<std::uint16_t>& values) override;
void poll() override; // watchdog
void reset() override;
private:
bool reconnect();
bool recv_all(void* buf, std::size_t len);
private:
// socket
int sock_;
std::uint16_t transaction_id_{0};
// connection info
std::string host_;
std::uint16_t port_{0};
// state machine
TransportState state_{TransportState::Disconnected};
TransportError last_error_{TransportError::None};
ModbusException exception_;
// watchdog
static constexpr int WATCHDOG_SEC = 5;
static constexpr int MAX_RETRY = 5;
static constexpr int FAULT_RESET_SEC = 30; // Fault 후 자동 리셋 대기
std::chrono::steady_clock::time_point last_ok_;
std::chrono::steady_clock::time_point fault_since_;
int retry_count_{0};
bool can_io() const;
};

View File

@@ -0,0 +1,47 @@
// TransportError / ModbusException (공통 에러 계층)
// transport_error.hpp
//
// enum class TransportError {
// None,
// Disconnected,
// Timeout,
// ProtocolError,
// IllegalFunction,
// IllegalDataAddress,
// IllegalDataValue,
// SlaveDeviceFailure,
// Acknowledge,
// SlaveDeviceBusy,
// ModbusException
// }; IlegalFunction, IllegalDataAddress, IllegalDataValue, SlaveDeviceFailure 는 ModbusException 으로 통합
#pragma once
enum class TransportError {
None,
// connection / IO
Disconnected,
Timeout,
// framing / protocol
ProtocolError,
// remote device reported error (Modbus exception)
RemoteError,
// transient remote states
InProgress, // Modbus Acknowledge (0x05)
Busy, // Modbus SlaveDeviceBusy (0x06)
Fault,
};
// 통신 오류 코드 열거형

View File

@@ -0,0 +1,9 @@
#pragma once
enum class TransportState {
Disconnected,
Connecting,
Connected,
Reconnecting,
Fault
};

View File

@@ -0,0 +1,29 @@
#pragma once
#include "data_format.hpp"
namespace VendorFormat {
// Honeywell HC900 — FP B "Big Endian" (manual p.4, default)
// Wire: r0=bytes[4,3], r1=bytes[2,1] (4-3-2-1 order)
constexpr DataFormat HC900_FLOAT {
ByteOrder::BigEndian,
WordOrder::HighFirst,
RegisterOrder::Normal
};
// Standard Modbus big-endian float
constexpr DataFormat MODBUS_FLOAT {
ByteOrder::BigEndian,
WordOrder::HighFirst,
RegisterOrder::Normal
};
// Fully reversed (rare but exists)
constexpr DataFormat FULL_REVERSED {
ByteOrder::LittleEndian,
WordOrder::LowFirst,
RegisterOrder::Swapped
};
} // namespace VendorFormat

View File

@@ -0,0 +1,29 @@
// app_init.cpp
#include "controller.hpp"
#include "modbus_tcp.hpp"
#include "logger.hpp"
#include "app_init.hpp"
#include <memory>
#include <string>
// void init_system()
// {
// Logger::instance().set_file("/var/log/modbus/modbus_tcp.log");
// auto transport = std::make_unique<ModbusTCP>();
// controller = std::make_unique<Controller>(std::move(transport));
// }
// app_init.hpp 새로 만들고 반환 받는 구조로 새로 만듬
std::unique_ptr<Controller> init_system()
{
Logger::instance().set_file("/var/log/modbus/modbus_tcp.log");
auto transport = std::make_unique<ModbusTCP>();
return std::make_unique<Controller>(std::move(transport));
}

View File

@@ -0,0 +1,239 @@
#include "codec.hpp"
#include <cstring>
#include <endian.h>
// ------------------------------------------------------------
// helpers
// ------------------------------------------------------------
static inline std::uint16_t make_word(std::uint8_t hi, std::uint8_t lo)
{
return static_cast<std::uint16_t>((hi << 8) | lo);
}
static inline void split_word(std::uint16_t w,
std::uint8_t& hi,
std::uint8_t& lo)
{
hi = static_cast<std::uint8_t>((w >> 8) & 0xFF);
lo = static_cast<std::uint8_t>(w & 0xFF);
}
// ------------------------------------------------------------
// core generic helpers (N words)
// ------------------------------------------------------------
template<std::size_t N>
static std::array<std::uint16_t, N>
encode_words(const std::uint8_t* bytes, const DataFormat& fmt)
{
std::array<std::uint16_t, N> words{};
// byte → word
for (std::size_t i = 0; i < N; ++i) {
std::uint8_t hi, lo;
if (fmt.byte_order == ByteOrder::BigEndian) {
hi = bytes[i * 2];
lo = bytes[i * 2 + 1];
} else {
hi = bytes[i * 2 + 1];
lo = bytes[i * 2];
}
words[i] = make_word(hi, lo);
}
// word order
if (fmt.word_order == WordOrder::LowFirst && N >= 2) {
for (std::size_t i = 0; i < N / 2; ++i) {
std::swap(words[i], words[N - 1 - i]);
}
}
return words;
}
template<std::size_t N>
static void
decode_words(const std::array<std::uint16_t, N>& words,
std::uint8_t* bytes,
const DataFormat& fmt)
{
std::array<std::uint16_t, N> w = words;
// word order
if (fmt.word_order == WordOrder::LowFirst && N >= 2) {
for (std::size_t i = 0; i < N / 2; ++i) {
std::swap(w[i], w[N - 1 - i]);
}
}
// word → byte
for (std::size_t i = 0; i < N; ++i) {
std::uint8_t hi, lo;
split_word(w[i], hi, lo);
if (fmt.byte_order == ByteOrder::BigEndian) {
bytes[i * 2] = hi;
bytes[i * 2 + 1] = lo;
} else {
bytes[i * 2] = lo;
bytes[i * 2 + 1] = hi;
}
}
}
// ------------------------------------------------------------
// 32-bit signed / unsigned
// ------------------------------------------------------------
std::array<std::uint16_t, 2>
encode_int32(std::int32_t value, const DataFormat& fmt)
{
std::uint8_t b[4];
std::memcpy(b, &value, 4);
return encode_words<2>(b, fmt);
}
std::int32_t
decode_int32(std::uint16_t r0,
std::uint16_t r1,
const DataFormat& fmt)
{
std::uint8_t b[4];
decode_words<2>({ r0, r1 }, b, fmt);
std::int32_t value;
std::memcpy(&value, b, 4);
return value;
}
std::array<std::uint16_t, 2>
encode_uint32(std::uint32_t value, const DataFormat& fmt)
{
std::uint8_t b[4];
std::memcpy(b, &value, 4);
return encode_words<2>(b, fmt);
}
std::uint32_t
decode_uint32(std::uint16_t r0,
std::uint16_t r1,
const DataFormat& fmt)
{
std::uint8_t b[4];
decode_words<2>({ r0, r1 }, b, fmt);
std::uint32_t value;
std::memcpy(&value, b, 4);
return value;
}
// ------------------------------------------------------------
// float / double
// ------------------------------------------------------------
std::array<std::uint16_t, 2>
encode_float(float value, const DataFormat& fmt)
{
std::uint32_t u;
std::memcpy(&u, &value, 4);
// Convert host byte order → big-endian bytes before encoding words.
if (fmt.byte_order == ByteOrder::BigEndian)
u = htobe32(u);
std::uint8_t b[4];
std::memcpy(b, &u, 4);
return encode_words<2>(b, fmt);
}
float
decode_float(std::uint16_t r0,
std::uint16_t r1,
const DataFormat& fmt)
{
std::uint8_t b[4];
decode_words<2>({ r0, r1 }, b, fmt);
std::uint32_t u;
std::memcpy(&u, b, 4);
// decode_words produces big-endian bytes; convert to host byte order.
if (fmt.byte_order == ByteOrder::BigEndian)
u = be32toh(u);
float value;
std::memcpy(&value, &u, 4);
return value;
}
std::array<std::uint16_t, 4>
encode_double(double value, const DataFormat& fmt)
{
std::uint8_t b[8];
std::memcpy(b, &value, 8);
return encode_words<4>(b, fmt);
}
double
decode_double(std::uint16_t r0,
std::uint16_t r1,
std::uint16_t r2,
std::uint16_t r3,
const DataFormat& fmt)
{
std::uint8_t b[8];
decode_words<4>({ r0, r1, r2, r3 }, b, fmt);
double value;
std::memcpy(&value, b, 8);
return value;
}
// ------------------------------------------------------------
// 64-bit signed / unsigned
// ------------------------------------------------------------
std::array<std::uint16_t, 4>
encode_int64(std::int64_t value, const DataFormat& fmt)
{
std::uint8_t b[8];
std::memcpy(b, &value, 8);
return encode_words<4>(b, fmt);
}
std::int64_t
decode_int64(std::uint16_t r0,
std::uint16_t r1,
std::uint16_t r2,
std::uint16_t r3,
const DataFormat& fmt)
{
std::uint8_t b[8];
decode_words<4>({ r0, r1, r2, r3 }, b, fmt);
std::int64_t value;
std::memcpy(&value, b, 8);
return value;
}
std::array<std::uint16_t, 4>
encode_uint64(std::uint64_t value, const DataFormat& fmt)
{
std::uint8_t b[8];
std::memcpy(b, &value, 8);
return encode_words<4>(b, fmt);
}
std::uint64_t
decode_uint64(std::uint16_t r0,
std::uint16_t r1,
std::uint16_t r2,
std::uint16_t r3,
const DataFormat& fmt)
{
std::uint8_t b[8];
decode_words<4>({ r0, r1, r2, r3 }, b, fmt);
std::uint64_t value;
std::memcpy(&value, b, 8);
return value;
}

View File

@@ -0,0 +1,232 @@
#include "controller.hpp"
#include "codec.hpp"
#include <vector>
// ------------------------------------------------------------
// lifecycle
// ------------------------------------------------------------
Controller::Controller(std::unique_ptr<ITransport> transport)
: transport_(std::move(transport))
{
}
bool Controller::connect(const char* host, std::uint16_t port)
{
return transport_ && transport_->connect(host, port);
}
void Controller::disconnect()
{
if (transport_)
transport_->disconnect();
}
bool Controller::is_connected() const
{
return transport_ && transport_->is_connected();
}
void Controller::poll()
{
if (transport_)
transport_->poll();
}
// ------------------------------------------------------------
// raw register
// ------------------------------------------------------------
bool Controller::read_register(std::uint16_t addr, std::uint16_t& value)
{
if (!transport_ || !transport_->can_io())
return false;
std::vector<std::uint16_t> regs;
if (!transport_->read_registers(addr, 1, regs) || regs.size() != 1)
return false;
value = regs[0];
return true;
}
bool Controller::read_raw(std::uint16_t addr, std::uint16_t count, std::vector<std::uint16_t>& out)
{
if (!transport_ || !transport_->can_io()) return false;
return transport_->read_registers(addr, count, out);
}
bool Controller::write_register(std::uint16_t addr, std::uint16_t value)
{
if (!is_connected()) return false;
return transport_->write_registers(addr, { value });
}
// ------------------------------------------------------------
// 32-bit
// ------------------------------------------------------------
bool Controller::read_int32(std::uint16_t addr,
std::int32_t& value,
const DataFormat& fmt)
{
if (!transport_ || !transport_->can_io())
return false;
std::vector<std::uint16_t> regs;
if (!transport_->read_registers(addr, 2, regs) || regs.size() != 2)
return false;
value = decode_int32(regs[0], regs[1], fmt);
return true;
}
bool Controller::write_int32(std::uint16_t addr,
std::int32_t value,
const DataFormat& fmt)
{
if (!transport_ || !transport_->can_io())
return false;
auto r = encode_int32(value, fmt);
return transport_->write_registers(addr, { r[0], r[1] });
}
bool Controller::read_uint32(std::uint16_t addr,
std::uint32_t& value,
const DataFormat& fmt)
{
if (!transport_ || !transport_->can_io())
return false;
std::vector<std::uint16_t> regs;
if (!transport_->read_registers(addr, 2, regs) || regs.size() != 2)
return false;
value = decode_uint32(regs[0], regs[1], fmt);
return true;
}
bool Controller::write_uint32(std::uint16_t addr,
std::uint32_t value,
const DataFormat& fmt)
{
if (!transport_ || !transport_->can_io())
return false;
auto r = encode_uint32(value, fmt);
return transport_->write_registers(addr, { r[0], r[1] });
}
// ------------------------------------------------------------
// float / double
// ------------------------------------------------------------
bool Controller::read_float(std::uint16_t addr,
float& value,
const DataFormat& fmt)
{
if (!transport_ || !transport_->can_io())
return false;
std::vector<std::uint16_t> regs;
if (!transport_->read_registers(addr, 2, regs) || regs.size() != 2)
return false;
value = decode_float(regs[0], regs[1], fmt);
return true;
}
bool Controller::write_float(std::uint16_t addr,
float value,
const DataFormat& fmt)
{
if (!transport_ || !transport_->can_io())
return false;
auto r = encode_float(value, fmt);
return transport_->write_registers(addr, { r[0], r[1] });
}
bool Controller::read_double(std::uint16_t addr,
double& value,
const DataFormat& fmt)
{
if (!transport_ || !transport_->can_io())
return false;
std::vector<std::uint16_t> regs;
if (!transport_->read_registers(addr, 4, regs) || regs.size() != 4)
return false;
value = decode_double(regs[0], regs[1], regs[2], regs[3], fmt);
return true;
}
bool Controller::write_double(std::uint16_t addr,
double value,
const DataFormat& fmt)
{
if (!transport_ || !transport_->can_io())
return false;
auto r = encode_double(value, fmt);
return transport_->write_registers(addr, { r[0], r[1], r[2], r[3] });
}
// ------------------------------------------------------------
// 64-bit
// ------------------------------------------------------------
bool Controller::read_int64(std::uint16_t addr,
std::int64_t& value,
const DataFormat& fmt)
{
if (!transport_ || !transport_->can_io())
return false;
std::vector<std::uint16_t> regs;
if (!transport_->read_registers(addr, 4, regs) || regs.size() != 4)
return false;
value = decode_int64(regs[0], regs[1], regs[2], regs[3], fmt);
return true;
}
bool Controller::write_int64(std::uint16_t addr,
std::int64_t value,
const DataFormat& fmt)
{
if (!transport_ || !transport_->can_io())
return false;
auto r = encode_int64(value, fmt);
return transport_->write_registers(addr, { r[0], r[1], r[2], r[3] });
}
bool Controller::read_uint64(std::uint16_t addr,
std::uint64_t& value,
const DataFormat& fmt)
{
if (!transport_ || !transport_->can_io())
return false;
std::vector<std::uint16_t> regs;
if (!transport_->read_registers(addr, 4, regs) || regs.size() != 4)
return false;
value = decode_uint64(regs[0], regs[1], regs[2], regs[3], fmt);
return true;
}
bool Controller::write_uint64(std::uint16_t addr,
std::uint64_t value,
const DataFormat& fmt)
{
if (!transport_ || !transport_->can_io())
return false;
auto r = encode_uint64(value, fmt);
return transport_->write_registers(addr, { r[0], r[1], r[2], r[3] });
}

View File

@@ -0,0 +1,417 @@
#include "gateway.h"
#include "controller.hpp"
#include "modbus_tcp.hpp"
#include "vendor_formats.hpp"
#include "codec.hpp"
#include "logger.hpp"
#include "json.hpp"
#include <fstream>
#include <numeric>
#include <unistd.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
#include <grpcpp/server_context.h>
#include <google/protobuf/timestamp.pb.h>
// ─── Constructor / Destructor ───
Hc900Gateway::Hc900Gateway(const std::string& host, uint16_t port,
const std::string& map_path, int poll_interval_ms,
int grpc_port)
: host_(host), port_(port), poll_interval_ms_(poll_interval_ms),
grpc_listen_("0.0.0.0:" + std::to_string(grpc_port))
{
LoadRegisterMap(map_path);
auto transport = std::make_unique<ModbusTCP>();
controller_ = std::make_unique<Controller>(std::move(transport));
}
Hc900Gateway::~Hc900Gateway() { Stop(); }
// ─── Start / Stop ───
bool Hc900Gateway::Start()
{
Logger::instance().log("INFO", "[Gateway] Connecting to " + host_ + ":" + std::to_string(port_));
if (!controller_->connect(host_.c_str(), port_)) {
// 연결 실패해도 종료하지 않음 — 폴 루프에서 재접속 재시도
Logger::instance().log("WARN", "[Gateway] Initial connection failed. Will retry in poll loop...");
} else {
Logger::instance().log("INFO", "[Gateway] Connected.");
}
Logger::instance().log("INFO", "[Gateway] Starting poll thread (interval=" + std::to_string(poll_interval_ms_) + "ms)");
grpc_service_ = std::make_unique<GatewayServiceImpl>(*this);
grpc::ServerBuilder builder;
builder.AddListeningPort(grpc_listen_, grpc::InsecureServerCredentials());
builder.RegisterService(grpc_service_.get());
grpc_server_ = builder.BuildAndStart();
Logger::instance().log("INFO", "[Gateway] gRPC server listening on " + grpc_listen_);
running_ = true;
poll_thread_ = std::thread(&Hc900Gateway::PollLoop, this);
return true;
}
void Hc900Gateway::Stop()
{
running_ = false;
if (poll_thread_.joinable()) poll_thread_.join();
if (grpc_server_) grpc_server_->Shutdown();
controller_->disconnect();
}
// ─── Register Map Loading ───
void Hc900Gateway::LoadRegisterMap(const std::string& path)
{
std::ifstream f(path);
if (!f.is_open()) {
Logger::instance().log("ERROR", "[Gateway] Cannot open register map: " + path);
return;
}
auto j = nlohmann::json::parse(f);
for (const auto& item : j["registers"]) {
RegisterEntry e;
e.tag = item["tag"];
e.addr = item["addr"];
e.count = item.value("count", 2);
e.type = item.value("type", "float32");
e.access = item.value("access", "R");
registers_.push_back(e);
tag_index_[e.tag] = registers_.size() - 1;
}
// Build address-sorted index for batch reads
sorted_indices_.resize(registers_.size());
std::iota(sorted_indices_.begin(), sorted_indices_.end(), 0);
std::sort(sorted_indices_.begin(), sorted_indices_.end(),
[this](size_t a, size_t b){ return registers_[a].addr < registers_[b].addr; });
Logger::instance().log("INFO", "[Gateway] Loaded " + std::to_string(registers_.size()) + " registers from " + path);
}
// ─── Poll Loop ───
void Hc900Gateway::PollLoop()
{
while (running_) {
auto t0 = std::chrono::steady_clock::now();
if (controller_->is_connected()) {
ReadAllRegisters();
poll_count_++;
} else {
controller_->poll();
}
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - t0);
last_poll_duration_ = elapsed;
auto sleep_for = std::chrono::milliseconds(poll_interval_ms_) - elapsed;
if (sleep_for.count() > 0) {
std::this_thread::sleep_for(sleep_for);
}
}
}
void Hc900Gateway::ReadAllRegisters()
{
constexpr uint16_t MAX_BATCH = 120;
decltype(cache_) fresh;
size_t i = 0;
while (i < sorted_indices_.size()) {
uint32_t batch_start = registers_[sorted_indices_[i]].addr;
// Collect all registers that fit within [batch_start, batch_start + MAX_BATCH)
size_t j = i;
while (j < sorted_indices_.size()) {
const auto& e = registers_[sorted_indices_[j]];
if (e.addr + e.count - batch_start > MAX_BATCH) break;
++j;
}
// Read count = up to end of last register in this batch
const auto& last = registers_[sorted_indices_[j - 1]];
uint16_t read_count = static_cast<uint16_t>(last.addr + last.count - batch_start);
std::vector<uint16_t> regs;
bool ok;
{
std::lock_guard<std::mutex> lock(transport_mutex_);
ok = controller_->read_raw(static_cast<uint16_t>(batch_start), read_count, regs);
}
if (ok) {
auto now = std::chrono::system_clock::now();
for (size_t k = i; k < j; k++) {
const auto& entry = registers_[sorted_indices_[k]];
size_t off = entry.addr - batch_start;
CachedValue cv{};
cv.timestamp = now;
cv.quality = 192;
if (entry.type == "uint16") {
cv.is_float = false;
cv.uint16_val = regs[off];
} else {
cv.is_float = true;
cv.float32_val = decode_float(regs[off], regs[off + 1], VendorFormat::HC900_FLOAT);
}
fresh[entry.tag] = cv;
}
}
i = j;
}
{
std::lock_guard<std::mutex> lock(cache_mutex_);
cache_ = std::move(fresh);
}
}
CachedValue Hc900Gateway::ReadRegister(const RegisterEntry& entry)
{
CachedValue cv{};
cv.is_float = (entry.type == "float32");
cv.timestamp = std::chrono::system_clock::now();
cv.quality = 0;
if (!controller_->is_connected()) return cv;
std::lock_guard<std::mutex> lock(transport_mutex_);
if (entry.type == "uint16" && entry.count == 1) {
uint16_t v = 0;
if (controller_->read_register(entry.addr, v)) {
cv.uint16_val = v;
cv.quality = 192;
}
} else if (entry.type == "float32") {
float v = 0;
if (controller_->read_float(entry.addr, v, VendorFormat::HC900_FLOAT)) {
cv.float32_val = v;
cv.quality = 192;
}
}
return cv;
}
// ─── gRPC Service Implementation ───
Hc900Gateway::GatewayServiceImpl::GatewayServiceImpl(Hc900Gateway& gateway)
: gateway_(gateway) {}
namespace {
void TagValueFromCache(hc900::TagValue* tv, const std::string& name, const CachedValue& cv) {
tv->set_tag_name(name);
tv->set_quality(cv.quality);
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
cv.timestamp.time_since_epoch()).count();
tv->mutable_timestamp()->set_seconds(static_cast<int64_t>(ns / 1000000000));
tv->mutable_timestamp()->set_nanos(static_cast<int32_t>(ns % 1000000000));
if (cv.is_float) {
tv->set_float32_val(cv.float32_val);
} else {
tv->set_uint16_val(cv.uint16_val);
}
}
}
grpc::Status Hc900Gateway::GatewayServiceImpl::ReadTags(
grpc::ServerContext*,
const hc900::ReadTagsRequest* req,
hc900::ReadTagsResponse* resp)
{
std::lock_guard<std::mutex> lock(gateway_.cache_mutex_);
if (req->tag_names().empty()) {
for (const auto& [tag, cv] : gateway_.cache_) {
TagValueFromCache(resp->add_values(), tag, cv);
}
} else {
for (const auto& name : req->tag_names()) {
auto it = gateway_.cache_.find(name);
if (it == gateway_.cache_.end()) {
auto idx = gateway_.tag_index_.find(name);
if (idx != gateway_.tag_index_.end()) {
auto& entry = gateway_.registers_[idx->second];
it = gateway_.cache_.find(entry.tag);
}
}
if (it != gateway_.cache_.end()) {
TagValueFromCache(resp->add_values(), it->first, it->second);
}
}
}
return grpc::Status::OK;
}
grpc::Status Hc900Gateway::GatewayServiceImpl::WriteTag(
grpc::ServerContext*,
const hc900::WriteTagRequest* req,
hc900::WriteTagResponse* resp)
{
auto it = gateway_.tag_index_.find(req->tag_name());
if (it == gateway_.tag_index_.end()) {
resp->set_success(false);
resp->set_error("Tag not found");
return grpc::Status::OK;
}
auto& entry = gateway_.registers_[it->second];
if (entry.access != "RW") {
resp->set_success(false);
resp->set_error("Read-only tag");
return grpc::Status::OK;
}
bool ok = false;
{
std::lock_guard<std::mutex> lock(gateway_.transport_mutex_);
if (entry.type == "uint16") {
ok = gateway_.controller_->write_register(entry.addr,
static_cast<uint16_t>(req->value()));
} else if (entry.type == "float32") {
ok = gateway_.controller_->write_float(entry.addr,
static_cast<float>(req->value()),
VendorFormat::HC900_FLOAT);
}
}
resp->set_success(ok);
if (!ok) resp->set_error("Modbus write failed");
if (ok) {
std::lock_guard<std::mutex> lock(gateway_.cache_mutex_);
CachedValue cv;
cv.is_float = (entry.type == "float32");
if (cv.is_float) cv.float32_val = static_cast<float>(req->value());
else cv.uint16_val = static_cast<uint16_t>(req->value());
cv.quality = 192;
cv.timestamp = std::chrono::system_clock::now();
gateway_.cache_[entry.tag] = cv;
}
return grpc::Status::OK;
}
grpc::Status Hc900Gateway::GatewayServiceImpl::ListTags(
grpc::ServerContext*,
const hc900::ListTagsRequest* req,
hc900::ListTagsResponse* resp)
{
int count = 0;
for (const auto& entry : gateway_.registers_) {
if (!req->filter().empty()) {
auto lower_tag = entry.tag;
auto lower_filter = req->filter();
std::transform(lower_tag.begin(), lower_tag.end(), lower_tag.begin(), ::tolower);
std::transform(lower_filter.begin(), lower_filter.end(), lower_filter.begin(), ::tolower);
if (lower_tag.find(lower_filter) == std::string::npos) continue;
}
auto* meta = resp->add_tags();
meta->set_tag_name(entry.tag);
meta->set_address(entry.addr);
meta->set_count(entry.count);
meta->set_type(entry.type);
meta->set_access(entry.access);
count++;
if (req->limit() > 0 && count >= req->limit()) break;
}
return grpc::Status::OK;
}
grpc::Status Hc900Gateway::GatewayServiceImpl::HealthCheck(
grpc::ServerContext*,
const hc900::HealthCheckRequest*,
hc900::HealthCheckResponse* resp)
{
resp->set_status(gateway_.controller_->is_connected()
? hc900::HealthCheckResponse::SERVING
: hc900::HealthCheckResponse::NOT_SERVING);
resp->set_uptime_sec(0);
resp->set_poll_count(gateway_.poll_count_);
resp->set_last_poll_ms(static_cast<int32_t>(gateway_.last_poll_duration_.count()));
resp->set_controller_ip(gateway_.host_);
resp->set_active_tags(static_cast<int32_t>(gateway_.registers_.size()));
return grpc::Status::OK;
}
grpc::Status Hc900Gateway::GatewayServiceImpl::StreamTags(
grpc::ServerContext* ctx,
const hc900::StreamTagsRequest* req,
grpc::ServerWriter<hc900::TagValue>* writer)
{
int interval = req->interval_ms() > 0 ? req->interval_ms() : 1000;
std::vector<std::string> names;
if (req->tag_names().empty()) {
std::lock_guard<std::mutex> lock(gateway_.cache_mutex_);
for (const auto& [tag, _] : gateway_.cache_) {
names.push_back(tag);
}
} else {
names.assign(req->tag_names().begin(), req->tag_names().end());
}
while (!ctx->IsCancelled()) {
auto t0 = std::chrono::steady_clock::now();
{
std::lock_guard<std::mutex> lock(gateway_.cache_mutex_);
for (const auto& name : names) {
auto it = gateway_.cache_.find(name);
if (it == gateway_.cache_.end()) continue;
auto& cv = it->second;
hc900::TagValue tv;
TagValueFromCache(&tv, name, cv);
if (!writer->Write(tv)) return grpc::Status::CANCELLED;
}
}
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - t0);
auto sleep_for = std::chrono::milliseconds(interval) - elapsed;
if (sleep_for.count() > 0) {
std::this_thread::sleep_for(sleep_for);
}
}
return grpc::Status::OK;
}
// ─── main ───
int main(int argc, char* argv[])
{
std::string host = "192.168.0.240";
std::string map_path = "docs/register-map.json";
int poll_ms = 1000;
int grpc_port = 50051;
uint16_t modbus_port = 502;
if (argc > 1) host = argv[1];
if (argc > 2) map_path = argv[2];
if (argc > 3) poll_ms = std::atoi(argv[3]);
if (argc > 4) grpc_port = std::atoi(argv[4]);
if (argc > 5) modbus_port = static_cast<uint16_t>(std::atoi(argv[5]));
Logger::instance().set_file("/tmp/hc900_gateway.log");
Hc900Gateway gateway(host, modbus_port, map_path, poll_ms, grpc_port);
if (!gateway.Start()) {
return 1;
}
Logger::instance().log("INFO", "[Gateway] Running. Press Ctrl+C to stop.");
pause();
gateway.Stop();
return 0;
}

View File

@@ -0,0 +1,3 @@
// app_init.cpp
#include "app_init.hpp"
auto controller = init_system();

View File

@@ -0,0 +1,389 @@
#include "modbus_tcp.hpp"
#include "modbus_exception.hpp"
#include "transport_error.hpp"
#include "log_macros.hpp"
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <thread>
namespace {
constexpr std::uint8_t MODBUS_UNIT_ID = 1;
constexpr int SOCKET_TIMEOUT_SEC = 2;
constexpr int WATCHDOG_SEC = 5;
constexpr int MAX_RETRY = 5;
}
// ------------------------------------------------------------
// Modbus exception → TransportError
// ------------------------------------------------------------
static TransportError map_exception(ModbusException ex)
{
switch (ex) {
case ModbusException::Acknowledge:
return TransportError::InProgress;
case ModbusException::SlaveDeviceBusy:
return TransportError::Busy;
default:
return TransportError::RemoteError;
}
}
// ------------------------------------------------------------
// ctor / dtor
// ------------------------------------------------------------
ModbusTCP::ModbusTCP()
: sock_(-1),
transaction_id_(0),
state_(TransportState::Disconnected),
last_error_(TransportError::None),
exception_(ModbusException::IllegalFunction),
retry_count_(0)
{
}
ModbusTCP::~ModbusTCP()
{
disconnect();
}
// ------------------------------------------------------------
// connection
// ------------------------------------------------------------
bool ModbusTCP::connect(const char* host, std::uint16_t port)
{
host_ = host;
port_ = port;
LOG_INFO("ModbusTCP: Connecting start: " + host_ + ":" + std::to_string(port_));
sock_ = ::socket(AF_INET, SOCK_STREAM, 0);
if (sock_ < 0)
return false;
timeval tv{};
tv.tv_sec = SOCKET_TIMEOUT_SEC;
tv.tv_usec = 0;
::setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
::setsockopt(sock_, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
::inet_pton(AF_INET, host, &addr.sin_addr);
if (::connect(sock_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
LOG_ERROR("ModbusTCP: Connecting failed: " + host_ + ":" + std::to_string(port_));
disconnect();
return false;
}
state_ = TransportState::Connected;
retry_count_ = 0;
last_ok_ = std::chrono::steady_clock::now();
last_error_ = TransportError::None;
return true;
}
void ModbusTCP::disconnect()
{
LOG_INFO("ModbusTCP: Disconnecting: " + host_ + ":" + std::to_string(port_));
if (sock_ >= 0) {
::close(sock_);
sock_ = -1;
}
state_ = TransportState::Disconnected;
}
bool ModbusTCP::is_connected() const
{
return state_ == TransportState::Connected;
}
// ------------------------------------------------------------
// TCP fragmentation safe recv
// ------------------------------------------------------------
bool ModbusTCP::recv_all(void* buf, std::size_t len)
{
std::uint8_t* p = static_cast<std::uint8_t*>(buf);
std::size_t total = 0;
while (total < len) {
ssize_t n = ::recv(sock_, p + total, len - total, 0);
if (n <= 0)
return false;
total += static_cast<std::size_t>(n);
}
return true;
}
// ------------------------------------------------------------
// status to log string helper
// ------------------------------------------------------------
static const char* to_string(TransportState s) {
switch (s) {
case TransportState::Disconnected: return "Disconnected";
case TransportState::Connected: return "Connected";
case TransportState::Reconnecting: return "Reconnecting";
case TransportState::Fault: return "Fault";
default: return "Unknown";
}
}
// ------------------------------------------------------------
// Read Holding Registers (0x03)
// ------------------------------------------------------------
bool ModbusTCP::read_registers(std::uint16_t addr,
std::uint16_t count,
std::vector<std::uint16_t>& out)
{
if (!can_io()) {
last_error_ = TransportError::Disconnected;
return false;
}
if (count == 0) {
last_error_ = TransportError::ProtocolError;
return false;
}
// MBAP(7) + PDU(5)
std::uint8_t req[12]{};
req[0] = transaction_id_ >> 8;
req[1] = transaction_id_ & 0xFF;
req[2] = 0x00;
req[3] = 0x00;
req[4] = 0x00;
req[5] = 0x06;
req[6] = MODBUS_UNIT_ID;
req[7] = 0x03;
req[8] = addr >> 8;
req[9] = addr & 0xFF;
req[10] = count >> 8;
req[11] = count & 0xFF;
if (::send(sock_, req, sizeof(req), 0) < 0) {
last_error_ = TransportError::Disconnected;
return false;
}
std::uint8_t header[9];
if (!recv_all(header, 9)) {
last_error_ = TransportError::Timeout;
return false;
}
std::uint8_t func = header[7];
if (func & 0x80) {
exception_ = static_cast<ModbusException>(header[8]);
last_error_ = map_exception(exception_);
return false;
}
std::uint8_t byte_count = header[8];
std::vector<std::uint8_t> payload(byte_count);
if (!recv_all(payload.data(), byte_count)) {
last_error_ = TransportError::Timeout;
return false;
}
if (byte_count != count * 2) {
last_error_ = TransportError::ProtocolError;
return false;
}
out.clear();
out.reserve(count);
for (std::size_t i = 0; i < count; ++i) {
out.push_back((payload[i * 2] << 8) | payload[i * 2 + 1]);
}
transaction_id_++;
last_ok_ = std::chrono::steady_clock::now();
last_error_ = TransportError::None;
return true;
}
// ------------------------------------------------------------
// Write Multiple Registers (0x10)
// ------------------------------------------------------------
bool ModbusTCP::write_registers(std::uint16_t addr,
const std::vector<std::uint16_t>& values)
{
if (!can_io()) {
last_error_ = TransportError::Disconnected;
return false;
}
if (values.empty()) {
last_error_ = TransportError::ProtocolError;
return false;
}
std::size_t count = values.size();
std::size_t data_len = count * 2;
std::size_t pdu_len = 6 + data_len;
std::size_t length = 1 + pdu_len;
std::vector<std::uint8_t> req(7 + pdu_len);
req[0] = transaction_id_ >> 8;
req[1] = transaction_id_ & 0xFF;
req[2] = 0x00;
req[3] = 0x00;
req[4] = length >> 8;
req[5] = length & 0xFF;
req[6] = MODBUS_UNIT_ID;
req[7] = 0x10;
req[8] = addr >> 8;
req[9] = addr & 0xFF;
req[10] = count >> 8;
req[11] = count & 0xFF;
req[12] = static_cast<std::uint8_t>(data_len);
for (std::size_t i = 0; i < count; ++i) {
req[13 + i * 2] = values[i] >> 8;
req[14 + i * 2] = values[i] & 0xFF;
}
if (::send(sock_, req.data(), req.size(), 0) < 0) {
last_error_ = TransportError::Disconnected;
return false;
}
std::uint8_t resp[12];
if (!recv_all(resp, sizeof(resp))) {
last_error_ = TransportError::Timeout;
return false;
}
std::uint8_t func = resp[7];
if (func & 0x80) {
exception_ = static_cast<ModbusException>(resp[8]);
last_error_ = map_exception(exception_);
return false;
}
if (func != 0x10) {
last_error_ = TransportError::ProtocolError;
return false;
}
transaction_id_++;
last_ok_ = std::chrono::steady_clock::now();
last_error_ = TransportError::None;
return true;
}
// ------------------------------------------------------------
// watchdog / reconnect / log state changes(added)
// ------------------------------------------------------------
void ModbusTCP::poll()
{
using namespace std::chrono;
auto now = steady_clock::now();
auto prev = state_;
switch (state_) {
case TransportState::Connected: {
auto idle = duration_cast<seconds>(now - last_ok_);
if (idle.count() > WATCHDOG_SEC) {
last_error_ = TransportError::Timeout;
state_ = TransportState::Reconnecting;
}
break;
}
case TransportState::Disconnected:
case TransportState::Reconnecting:
reconnect();
break;
case TransportState::Fault: {
// FAULT_RESET_SEC 후 자동 리셋 → Disconnected로 복귀해 재시도
auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::steady_clock::now() - fault_since_).count();
if (elapsed >= FAULT_RESET_SEC) {
LOG_WARN("[Transport] Fault 상태 리셋 — 재접속 시도");
retry_count_ = 0;
state_ = TransportState::Disconnected;
}
break;
}
}
if (prev != state_) {
LOG_WARN(std::string("state: ") +
to_string(prev) + " -> " +
to_string(state_));
}
}
// ------------------------------------------------------------
// reset procedure
// ------------------------------------------------------------
bool ModbusTCP::reconnect()
{
LOG_DEBUG("reconnect attempt " + std::to_string(retry_count_));
if (retry_count_++ >= MAX_RETRY) {
state_ = TransportState::Fault;
fault_since_ = std::chrono::steady_clock::now();
LOG_ERROR("reconnect failed, entering Fault (will retry in " +
std::to_string(FAULT_RESET_SEC) + "s)");
return false;
}
disconnect();
std::this_thread::sleep_for(std::chrono::milliseconds(500));
return connect(host_.c_str(), port_);
}
// ------------------------------------------------------------
// reset procedure
// ------------------------------------------------------------
void ModbusTCP::reset()
{
disconnect();
transaction_id_ = 0;
retry_count_ = 0;
last_error_ = TransportError::None;
exception_ = ModbusException::IllegalFunction; // 의미 없는 초기값 OK
state_ = TransportState::Disconnected;
}
// ------------------------------------------------------------
// read/write allowed check
// ------------------------------------------------------------
inline bool ModbusTCP::can_io() const
{
return state_ == TransportState::Connected;
}