# 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?