콘텐츠로 이동
무료 평가 시작

PDU, ADU와 기능 코드

Modbus 메시지는 두 겹입니다. 안쪽의 PDU(Protocol Data Unit)는 전송 방식과 무관하고, 바깥쪽의 ADU(Application Data Unit)는 전송 방식마다 다릅니다. 이 페이지는 MODBUS Application Protocol Specification V1.1b3의 §4.1 프로토콜 설명, §5 기능 코드 분류, §6 기능 코드 설명, §7 예외 응답을 근거로 합니다.

PDU는 기능 코드 1바이트와 데이터로 이뤄집니다. 최대 길이는 253바이트입니다.

+---------------+----------------------------+
| 기능 코드 1B | 데이터 0~252B |
+---------------+----------------------------+

보유 레지스터 0을 하나 읽는 요청과 응답은 다음과 같습니다.

요청 PDU 03 0000 0001 기능 03, 시작 주소 0, 수량 1
응답 PDU 03 02 002A 기능 03, 바이트 수 2, 값 0x002A(42)

보유 레지스터 0에 42를 쓰는 요청은 06 0000 002A이고, 정상 응답은 요청과 같은 5바이트입니다.

PDComm은 PDU를 16진수 문자열("0300000001")이나 바이트 배열([3,0,0,0,1])로 받습니다. 응답은 10진수 바이트 배열([3,2,0,42])로 돌려줍니다. MBAP 헤더, 유닛 주소, CRC·LRC는 PDU에 넣지 않습니다. 전송 계층이 붙이고 뗍니다.

ADU는 PDU 앞뒤에 주소와 오류 검사를 붙인 것입니다. 같은 읽기 요청이 전송 방식마다 다음처럼 보입니다.

전송 ADU 구조 최대 길이 같은 요청의 바이트
Modbus TCP MBAP 헤더 7B + PDU 260B 00 01 00 00 00 06 01 03 00 00 00 01
RTU 유닛 주소 1B + PDU + CRC 2B 256B 01 03 00 00 00 01 84 0A
ASCII : + 16진 문자(주소, PDU, LRC) + CR LF 513자 :010300000001FB + CR LF

명세 §5는 기능 코드를 세 가지로 나눕니다.

분류 범위 설명
공개(public) 164, 7399, 111~127 중 정의된 코드 Modbus Organization이 정의하고 검증한 코드입니다.
사용자 정의(user-defined) 6572, 100110 제조사가 자유롭게 정의합니다. 다른 제조사 장비와 호환을 보장하지 않습니다.
예약(reserved) 그 밖의 일부 코드 일부 회사의 기존 제품이 사용하므로 새로 쓰지 않습니다.

128 이상은 예외 응답용입니다. 요청의 기능 코드에 0x80을 더한 값이 예외 응답의 기능 코드입니다.

PDComm은 다음 19개 공개 기능 코드를 지원합니다. capabilities 명령의 functions 필드도 같은 목록을 돌려줍니다.

코드(10진/16진) 이름 명세 요청 PDU 예 PDComm 제한
1 / 0x01 Read Coils §6.1 0100000008 수량 1~2000
2 / 0x02 Read Discrete Inputs §6.2 0200000008 수량 1~2000
3 / 0x03 Read Holding Registers §6.3 0300000001 수량 1~125
4 / 0x04 Read Input Registers §6.4 0400000001 수량 1~125
5 / 0x05 Write Single Coil §6.5 050000FF00 값은 FF00(켜짐) 또는 0000(꺼짐)
6 / 0x06 Write Single Register §6.6 060000002A
7 / 0x07 Read Exception Status §6.7 07 직렬 전용
8 / 0x08 Diagnostics §6.8 0800001234 직렬 전용, 아래 표의 하위 기능
11 / 0x0B Get Comm Event Counter §6.9 0B 직렬 전용
12 / 0x0C Get Comm Event Log §6.10 0C 직렬 전용, 최근 이벤트 64개
15 / 0x0F Write Multiple Coils §6.11 0F0000000801A5 수량 1~1968
16 / 0x10 Write Multiple Registers §6.12 1000000001020009 수량 1~123
17 / 0x11 Report Server ID §6.13 11 직렬 전용
20 / 0x14 Read File Record §6.14 140706000100000001 파일 번호 1 이상, 레코드 0~9999
21 / 0x15 Write File Record §6.15 1509060001000000010009 모든 레코드 범위를 먼저 검사한 뒤 씁니다.
22 / 0x16 Mask Write Register §6.16 160000FF000055 결과 = (현재값 AND And_Mask) OR (Or_Mask AND NOT And_Mask)
23 / 0x17 Read/Write Multiple Registers §6.17 170000000100000001020009 읽기 1125, 쓰기 1121, 쓰기 후 읽기
24 / 0x18 Read FIFO Queue §6.18 180000 큐 길이 최대 31, 읽어도 큐를 비우지 않습니다.
43 / 0x2B Read Device Identification (MEI 14) §6.21 2B0E0100 읽기 코드 1(basic)~4(individual)
  • 직렬 전용 기능은 명세가 Serial Line 전용으로 정한 기능입니다. PDComm TCP 서버는 예외 01로 응답하고, PDComm TCP 클라이언트는 요청을 보내지 않고 Unsupported 오류를 돌려줍니다.
  • MEI 13(CANopen General Reference, §6.20)은 내용을 해석하지 않는 확장 인터페이스입니다. 기본 서버는 예외 01로 응답합니다.
  • 사용자 정의 코드도 기본 서버에서는 예외 01입니다.

진단 기능은 하위 기능 코드(sub-function) 2바이트와 데이터 2바이트를 보냅니다. PDComm은 다음 15개를 지원합니다.

하위 기능(10진/16진) 이름 요청 PDU 응답
0 / 0x0000 Return Query Data 0800001234 데이터를 그대로 돌려줍니다.
1 / 0x0001 Restart Communications Option 0800010000 응답한 뒤 통신을 재시작하고 카운터를 지웁니다. 데이터 FF00이면 이벤트 로그도 지웁니다.
2 / 0x0002 Return Diagnostic Register 0800020000 진단 레지스터 값
3 / 0x0003 Change ASCII Input Delimiter 0800030A00 응답한 뒤 ASCII 종료 문자를 바꿉니다.
4 / 0x0004 Force Listen Only Mode 0800040000 응답하지 않고 청취 전용 모드로 들어갑니다.
10 / 0x000A Clear Counters and Diagnostic Register 08000A0000 카운터와 진단 레지스터를 지웁니다.
11 / 0x000B Return Bus Message Count 08000B0000 버스에서 본 메시지 수
12 / 0x000C Return Bus Communication Error Count 08000C0000 CRC·LRC 오류 수
13 / 0x000D Return Bus Exception Error Count 08000D0000 보낸 예외 응답 수
14 / 0x000E Return Server Message Count 08000E0000 이 서버 앞으로 온 메시지 수
15 / 0x000F Return Server No Response Count 08000F0000 응답하지 않은 메시지 수
16 / 0x0010 Return Server NAK Count 0800100000 NAK 수
17 / 0x0011 Return Server Busy Count 0800110000 Busy 예외 수
18 / 0x0012 Return Bus Character Overrun Count 0800120000 문자 오버런 수
20 / 0x0014 Clear Overrun Counter and Flag 0800140000 오버런 카운터와 플래그를 지웁니다.

청취 전용 모드의 서버는 어떤 요청에도 응답하지 않습니다. 빠져나오는 방법은 하위 기능 1(Restart Communications Option)뿐이며, 이 요청에도 응답은 오지 않습니다.

서버가 요청을 처리할 수 없으면 예외 응답(exception response)을 보냅니다. 예외 응답 PDU는 2바이트입니다.

요청 PDU 03 FFFF 0001 주소 65535부터 1개 읽기
예외 응답 83 02 0x03 + 0x80, 예외 코드 02

명세 §7의 예외 코드는 다음과 같습니다.

코드 이름 의미
01 Illegal Function 서버가 이 기능 코드를 지원하지 않거나 지금 상태에서 허용하지 않습니다.
02 Illegal Data Address 주소, 또는 주소와 수량의 조합이 서버에 없습니다.
03 Illegal Data Value 요청 데이터의 값이나 길이가 올바르지 않습니다.
04 Server Device Failure 요청을 처리하다 복구할 수 없는 오류가 났습니다.
05 Acknowledge 오래 걸리는 요청을 받아들였습니다. 결과는 나중에 조회합니다.
06 Server Device Busy 서버가 다른 일을 처리하고 있습니다. 나중에 다시 보냅니다.
08 Memory Parity Error 파일 레코드 메모리에서 패리티 오류를 찾았습니다.
0A Gateway Path Unavailable 게이트웨이에 해당 대상으로 가는 경로가 없습니다.
0B Gateway Target Device Failed to Respond 게이트웨이가 대상 장비의 응답을 받지 못했습니다.

예외 응답은 정상적인 Modbus 응답입니다. PDComm에서 예외 응답을 받은 request나 execute는 호출 자체가 성공하고, 결과의 status가 exception입니다. 반면 연결 실패, 시간 초과, 잘못된 JSON, 라이선스 없는 connect는 호출이 실패합니다. C API는 pdcomm_modbus_call에서 PDCOMM_MODBUS_SERVICE_ERROR를 돌려주고, C++과 .NET은 예외를 던집니다.

{"ok":true,"result":{"response":[131,2],"source":"local","status":"exception"}}

PDComm 서버가 언제 어떤 예외를 보내는지는 예외 응답 문제 해결에 정리했습니다.

PDComm은 같은 PDU를 두 가지 방법으로 처리합니다. 결과의 source 필드로 구분합니다.

명령 source 처리
execute local 연결 없이 엔드포인트 자신의 데이터 모델에서 실행합니다. 서버 동작을 확인하는 데 씁니다.
request wire 연결된 클라이언트가 실제로 상대에게 보내고 응답을 받습니다.

local 결과는 통신 성공의 증거가 아닙니다. 실제 장비와 통신했는지는 wire 결과로 확인합니다.