DNP3 驱动
概述
IEEE 1815 标准 DNP3(Distributed Network Protocol),是电力/供水/燃气 utility SCADA 的事实标准。 Master(client)通过 TCP 连接到 outstation(server),使用 Application Layer READ 采集测量值(Analog Input / Binary Input / Counter)。
| 项目 | 值 |
|---|---|
opc_type | DNP3 |
| 实现类 | plantpulse.driver.protocol.dnp3.DNP3Driver |
| 库 | 自研 Java 实现(无外部依赖) |
| read | ✅(单点 + class poll) |
| write | ✅(G12V1 CROB、G41V1~V4 Analog Output) |
| 安全 | 无(未实现 DNP3-SA) |
| 默认端口 | 20000 (TCP) |
类结构
| 类 | 作用 |
|---|---|
DNP3Driver | TCP socket / AL+TL+DLL 组装 / 单点 read / class poll / write |
DnpDataLink | 10 字节 DLL 头(start 0x05 0x64)+ 每 16 字节块的 LE CRC |
DnpTransport | 1 字节 TL 头(FIN/FIR/SEQ 6-bit) |
DnpApplication | Function Code、IIN、Object header、qualifier、response 解析器 |
DnpObject | Group 1/2/10/12/20/30/32/40/41 的对象编码器/解码器 |
DnpCrc | DNP3 专用 CRC-16(poly 0x3D65、reflected 0xA6BC、~complement、LE 序列化) |
DnpAddress | gNvM.idx / classN 地址解析器 |
Wire 格式
TCP payload =
DLL header(10 byte: start 0x0564 + len + ctl + dst LE + src LE + CRC LE)
+ 16-byte 블록마다 user data + LE CRC
↳ TL byte (1: FIN/FIR + SEQ 0..63)
↳ AL bytes:
byte 0 App Control (FIR/FIN/CON/UNS + SEQ 0..15)
byte 1 Function Code (1=READ, 5=DIRECT_OPERATE, 129=RESPONSE)
byte 2.. Object header (group + variation + qualifier) + range/data
CRC:DnpCrc.compute(data) — table-driven,init 0,reflected 0xA6BC,最后 ~crc,LE 2 字节序列化。
已验证 vector:[05 64 05 C9 01 00 00 04] → CRC 0xE521(LE 21 E5)。
OPC 注册选项
| 字段 | 含义 | 默认值 |
|---|---|---|
opc_agent_ip / opc_agent_port | outstation IP / 端口 | port 为 0 时使用 20000 |
options.master-address | DNP3 master DLL 地址 | 1 |
options.outstation-address | outstation DLL 地址 | 10 |
options.connect-timeout | TCP connect 超时(ms) | 3000 |
options.read-timeout | read SO 超时(ms) | 5000 |
标签 plc_address 格式
| 表示法 | 含义 |
|---|---|
g30v1.5 | Group 30 Var 1、point 5 — Analog Input 32-bit signed(带 flag) |
g30v5.0 | Analog Input 32-bit float |
g30v6.0 | Analog Input 64-bit double |
g1v2.0 | Binary Input 0(带 flag) |
g20v1.0 | 32-bit Counter |
g40v1.0 | Analog Output 32-bit |
class0 | Integrity poll (G60V1) — Static + 所有 class |
class1 ~ class3 | Event class poll (G60V2/V3/V4) |
class poll 触发一次后会缓存响应(lastValueByKey)。后续单点 read 若命中缓存则立即返回。
write 地址(g12v1.N + value):
| 输入 value | CROB op |
|---|---|
Latch_On 或 1 | opType=3 (Latch_On)、TCC=0 |
Latch_Off 或 0 | opType=4 (Latch_Off)、TCC=0 |
Pulse_On:<onMs>:<offMs>:<count> | opType=1 |
Close / Trip | TCC=1 (Close) / TCC=2 (Trip) |
g41v1..g41v4 分别为 32-bit signed / 16-bit signed / 32-bit float / 64-bit double 的 Analog Output。
不支持的范围
- DNP3-SA(Secure Authentication,IEEE 1815-2012 §7)。
- 多段(Multi-segment)TL 响应(当前仅发送 single-segment FIR=FIN=1)。
- Unsolicited responses (FC 130) 的异步接收 — 可以发送,但客户端侧未实现 unsolicited handler。
- File transfer (FC 25-30)、Time sync(FC 23 DELAY_MEASURE 仅定义了常量)。
测试覆盖率
test/java/plantpulse/driver/protocol/dnp3/
| 测试 | 验证内容 |
|---|---|
DnpCrcTest | spec vector + 任意长度 CRC |
DnpDataLinkTest | 10 字节头 + block CRC round-trip |
DnpTransportTest | FIN/FIR/SEQ 编码 |
DnpApplicationTest / DnpApplicationWriteTest | READ/DIRECT_OPERATE 构建、IIN 解码 |
DnpObjectTest / DnpObjectWriteTest | G1/G30/G40/G12V1/G41 编码器/解码器 |
DnpAddressTest / DnpAddressWriteTest | 地址解析器 |
DNP3DriverTest | 使用 mock outstation 的 read/write 端到端测试 |
DnpSpecExtraTest | 追加的 spec 符合性 |
参考
- IEEE 1815-2012,"DNP3 Specification"。
- 代码:
plantpulse-edge-driver/src/plantpulse/driver/protocol/dnp3/。 - 运维:必须与 outstation 侧的 master/outstation address 保持一致。不一致时会在 DLL 头处被立即丢弃。