Files
HC900-Crawler/industrial-comm/src-old/old_controller.cpp
windpacer 16fc7a2598 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>
2026-06-03 20:28:14 +09:00

148 lines
3.2 KiB
C++

#include "controller.hpp"
#include "codec.hpp"
#include "modbus_tcp.hpp"
#include <iostream>
Controller::Controller()
: connected_(false)
{
}
// ---- connection management ------------------------------------
bool Controller::connect(const std::string& address)
{
transport_ = std::make_unique<ModbusTCP>();
if (!transport_->connect(address.c_str(), 502)) {
return false;
}
connected_ = true;
address_ = address;
return true;
}
void Controller::disconnect()
{
if (connected_) {
std::cout << "Disconnected from controller at " << address_ << std::endl;
}
connected_ = false;
address_.clear();
}
bool Controller::is_connected() const
{
return connected_;
}
// ---- PLC-style raw register API ----------------------------------
bool Controller::read_register(std::uint16_t address,
std::uint16_t& value)
{
std::vector<std::uint16_t> regs;
if (!transport_->read_registers(address, 1, regs)) {
return false;
}
value = regs[0];
return true;
}
bool Controller::write_register(std::uint16_t address,
std::uint16_t value)
{
return transport_->write_registers(address, { value });
}
// ---- PLC-style float API ------------------------⭐
bool Controller::read_float(std::uint16_t address,
float& value,
const DataFormat& fmt)
{
if (!connected_) {
return false;
}
std::vector<std::uint16_t> regs;
if (!transport_->read_registers(address, 2, regs)) {
return false;
}
if (regs.size() != 2) {
return false;
}
value = decode_float(regs[0], regs[1], fmt);
return true;
}
bool Controller::write_float(std::uint16_t address,
float value,
const DataFormat& fmt)
{
if (!connected_) {
return false;
}
// float → 2 registers
auto regs = encode_float(value, fmt);
std::vector<std::uint16_t> values = {
regs[0], regs[1]
};
return transport_->write_registers(address, values);
}
// ---- PLC-style double API ----------------------------------
bool Controller::read_double(std::uint16_t address,
double& value,
const DataFormat& fmt)
{
if (!connected_) {
return false;
}
// read 4 consecutive registers atomically
std::vector<std::uint16_t> regs;
if (!transport_->read_registers(address, 4, regs)) {
return false;
}
if (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 address,
double value,
const DataFormat& fmt)
{
if (!connected_) {
return false;
}
// double → 4 registers
auto regs = encode_double(value, fmt);
std::vector<std::uint16_t> values = {
regs[0], regs[1], regs[2], regs[3]
};
return transport_->write_registers(address, values);
}