# HC900 직접 통신 아키텍처 브레인스토밍

참고: `51-52-25-111-HC900-Process-Controller-Communications-manual.pdf` (Rev 13, April 2017)

---

## HC900 Modbus 통신 요약 (매뉴얼 기반)

### 기본 프로토콜
- Modbus TCP (Ethernet) + Modbus RTU (RS232/RS485)
- IP 기본값: 192.168.1.254
- 최대 동시 연결: C30/C50=5, C70/C70R=10
- Unit ID: Modbus TCP에서는 사용 안 함 (00)
- Double Register Format: HC900 기본값은 **FP B (Big Endian)** — 4,3,2,1 byte 순서
  - Experion/Honeywell PlantScape는 FP B 사용
  - Modicon/Wonderware 표준은 **FP LB (Little Endian Byte-Swapped)** — 2,1,4,3

### 지원 Function Code
| Code | 기능 | HC900 사용 |
|---|---|---|
| 03 | Read Holding Registers | **주력** — float/int holding register 읽기 |
| 04 | Read Input Registers | Analog Input 전용 (v4.0+에서 03 대체) |
| 06 | Preset Single Register | Integer 단일 레지스터 쓰기 |
| 16 (10h) | Preset Multiple Registers | Float 다중 레지스터 쓰기 |
| 01/02 | Read Digital Output/Input | DI/DO 전용 |
| 05 | Force Single Coil | DO 제어 |

### Fixed Map 개요 (Table 6-1)

| 시작 주소 | 끝 주소 | 내용 | 비고 |
|---|---|---|---|
| 0000 | 003F | 시스템 파라미터 | Instrument Mode, Load Recipe 등 |
| 0040 | 00FF | Loop #1 (PID) | 192bytes: PV, SP, OP, alarms, mode 등 |
| 0140 | 01FF | Loop #2 | Loop마다 256(0x100) offset |
| ... | ... | Loop #3~#24 | |
| 1800 | 187F | Analog Input #1~#64 | FC03 전용, Rack#1 첫 8슬롯만 (v4.0+ 불가) |
| 18C0 | 1D6F | Variable #1~#600 | R/W 가능 |
| 2000 | 27CF | Signal Tag #1~#1000 | Legacy, Read-only |
| 3B60 | 5A9F | Signal Tag #1~#4000 | HC900 범위, Read-only |
| B000 | B3E7 | User Defined | R/W (signal=read-only, variable=R/W) |
| 7840 | 7FFF | Loop #25~#32 | 확장 루프 |

### Loop 파라미터 (Table 6-3, Loop #1 기준)

| Offset | 파라미터 | Type | Access |
|--------|---------|------|--------|
| +00 | PV | float | R |
| +02 | Remote SP (SP2) | float | R/W |
| +04 | Working SP | float | R/W |
| +06 | Output (OP) | float | R/W |
| +0C | PV (중복) | float | R |
| +0E | PV (다른 타입) | float | R |
| +2A | LSP #1 | float | R/W |
| +5A | Auto/Manual State | bit | R/W |
| +5E | Loop Status | bit | R |
| +BA | Enable/Disable Fuzzy | bit | R/W |
| +BB | Demand Tune Request | bit | R/W |
| +BD | SP State (SP1/SP2 선택) | bit | R/W |
| +BE | Remote/Local SP State | bit | R/W |
| +BF | Tune Set State | bit | R/W |

루프마다 192개(0xC0) 레지스터 사용. Loop #N 시작주소 = `0x40 + (N-1) * 0x100`

### Signal Tags (Table 6-11)
- Legacy: 2000~27CF (#1~#1000), HC900: 3B60~5A9F (#1~#4000)
- 각 태그는 float 2-register 사용 (even address)
- **Tag 번호와 실제 태그명의 매핑은 HC Designer의 "Tag Information" 리포트에서 확인**
- Read-only

### Variables (Table 6-5)
- 18C0~1D6F (#1~#600)
- 각 2-register float
- R/W 가능

### Float 포맷 (매뉴얼 3장)
HC900 컨트롤러는 Double Register Format을 설정 가능:
- **FP B** (기본): Big Endian — Byte4,3,2,1 → Reg N(High)=Byte4,3 / Reg N+1(Low)=Byte2,1
- **FP LB**: Little Endian Byte-Swapped — Byte2,1,4,3 → Reg N(High)=Byte2,1 / Reg N+1(Low)=Byte4,3

**HC900_FLOAT 포맷 (= FP B)**: BigEndian byte order + LowFirst (word swap)??

## 현재 구성 요소

| 구성 요소 | 플랫폼 | 통신 방식 | 용도 |
|---|---|---|---|
| **ExperionCrawler** | Ubuntu (C# .NET 8) | OPC UA → Experion HS R530 | OPC UA 데이터 수집/저장/API |
| **industrial-comm** | Ubuntu (C++17) | Modbus TCP → HC900 | HC900 Modbus TCP 라이브러리 (libcomm_core.so) |
| **NKOpcTunnel** | Windows (C++) | OPC Classic 터널링 (TCP/IP) | DCOM 없는 OPC Classic 통신 (본 프로젝트와 무관) |

## 목표

ExperionCrawler의 OPC UA → Experion 경로를 **Modbus TCP → HC900** 경로로 대체한 변형 버전 제작.

Experion을 거치지 않고 HC900과 직접 통신.

## 제안 아키텍처

```
HC900 Controller
    │  Modbus TCP (port 502)
    ▼
industrial-comm (C++ gateway, standalone process)
    │  gRPC
    ▼
HC900Crawler (C# .NET 8, ExperionCrawler 변형)
    │  EF Core
    ▼
PostgreSQL (iiot_platform)
```

## 필요한 작업

### Phase 1: C++ 게이트웨이 완성

- main.cpp 에 gRPC 서버 추가
- gRPC proto 정의 (ReadTag, WriteTag, ReadMultiple, BrowseRegisterMap)
- watchdog 스레드 실제 구현 확인
- cmake에 modbus_tcp.cpp, app_init.cpp 포함

### Phase 2: C# 변형 앱

ExperionCrawler에서 OPC UA 계층을 gRPC Client로 교체:

| 기존 (OPC UA) | 변경 (Modbus TCP via gRPC) |
|---|---|
| IExperionOpcClient | IModbusTcpClient (gRPC 호출) |
| ExperionRealtimeService (Subscription) | Hc900RealtimeService (폴링 기반) |
| IExperionOpcWriteClient | IModbusWriteClient (gRPC write) |
| BrowseNodesAsync | Hc900RegisterMapLoader (설정 파일 기반) |

### Phase 3: 레지스터-태그 매핑

HC900은 OPC UA의 NodeId 개념이 없음 → 레지스터 주소-태그 매핑 필요

```json
{
  "registers": [
    { "address": 100, "tag": "TI-6101", "type": "float", "format": "HC900_FLOAT" },
    { "address": 102, "tag": "PIC-6102.SP", "type": "float", "format": "HC900_FLOAT" },
    { "address": 200, "tag": "XV-6201", "type": "uint16" }
  ]
}
```

## 유지되는 ExperionCrawler 기능

- DB 스키마 (realtime_table, history_table, event_history_table, tag_metadata)
- Background Service 패턴
- Web API / Controllers
- PostgreSQL + TimeScaleDB
- P&ID 관련 기능 (옵션)
- Feedforward Advisory (옵션)

## HC900 Modbus Mapping: Fixed vs Custom

HC900은 **두 가지** Modbus 레지스터 매핑 방식을 지원함 (매뉴얼 §1.1).

### 실무적 결론

- **대부분 Fixed Map을 기본 사용** — PID loop 32개 초과 같은 특별한 경우에만 Custom Map으로 전환
- **Custom Map으로 전환해도 Fixed Map의 주소 체계가 그대로 Custom Map으로 전달됨** (기존 주소 유지)
- 따라서 **매뉴얼의 Fixed Map (Table 6-1)이 실질적인 표준 주소 맵**



### Fixed Map (고정 맵)

| 특징 | 내용 |
|---|---|
| 제한된 파라미터, 제한된 수량 | 최대 32 loops, SP Programmer 4~8개 등 |
| 그룹화된 주소 범위 | Loop는 0x40~0xFF 범위 고정 |
| 모든 파라미터가 항상 매핑 | PID loop 40여개 파라미터 모두 |
| 편집 제한 | 주소 범위 내에서 이동만 가능 |
| **Firmware 무관** | 모든 HC900 버전에서 사용 가능 |

### Custom Map (사용자 정의 맵)

| 특징 | 내용 |
|---|---|
| 많은 파라미터 선택 가능 | 주소 범위만 허용하면 무제한에 가까움 |
| 선택적 매핑 | 필요한 파라미터만 골라서 할당 (예: PV, SP, OP만) |
| **유연한 주소 지정** | 어느 주소에나 할당 가능 |
| **추가 블록 지원** | Push Button, AGA, Calendar Event, XYR5000, UDC Loop 등 |
| **v4.0 이상만 가능** | |

### 핵심 차이점

```
Fixed Map:  PID Loop #1 → 항상 주소 0x40~0xFF (PV/SP/OP/Alarm/... 전부)
Custom Map: PID Loop #1 → 사용자가 지정한 주소 (PV만 별도 주소에 할당 가능)
```

→ **Custom Map을 사용하면 매뉴얼의 Fixed 주소 테이블이 적용되지 않음**
→ Custom Map의 주소는 **HC Designer에서 "Block Modbus Address" 리포트로만 확인 가능**

**확인 필요**: 대상 HC900 컨트롤러들이 Fixed Map을 쓰는지, Custom Map을 쓰는지?

## HC900 레지스터 맵 확보 방안

**HC900 Controller Designer Software**에서 통신레지스터 주소와 태그명을 추출 가능.

CDE 파일은 binary export 포맷이라 직접 파싱은 복잡했으나,
Designer 프로그램 자체에서 다음 리포트를 CSV/텍스트로 export 가능 (매뉴얼 §1.1):
1. **Tag Information Report** — Variables와 Signal Tags를 번호순 + Modbus 주소와 함께 리스트
2. **Block Modbus Address Report** — 모든 주요 블록의 시작 주소

설계 소프트웨어에서 추출해야 할 핵심 정보:
- 각 블록(AI/PID/AO)의 Modbus holding register 시작 주소
- 블록별 파라미터의 register offset map (PV, SP, OP, MODE 등)
- 블록 태그명 (예: "TI-6101", "PIC-6102")
- 데이터 타입 (float 2-register, uint16 1-register 등)

## 오픈 이슈

- [ ] C++ 게이트웨이 통신 방식: gRPC vs Unix Socket vs Raw TCP?
- [ ] 레지스터 맵 확보: CDE 파싱 재도전? JSON 수동 정의? 스캔 툴?
- [ ] ExperionCrawler를 fork? 아니면 같은 솔루션에 확장?
- [ ] HC900 float format 외에 다른 데이터 타입도 HC900 특화 포맷이 있는가?
- [ ] 프로젝트명: HC900Crawler? ModbusCrawler?
