PDU, ADU and function codes
A Modbus message has two layers. The inner PDU (protocol data unit) is the same on every transport; the outer ADU (application data unit) depends on the transport. This page is based on sections 4.1 (protocol description), 5 (function code categories), 6 (function code descriptions) and 7 (exception responses) of the MODBUS Application Protocol Specification V1.1b3.
A PDU is a one-byte function code followed by data, 253 bytes at most.
+------------------+-----------------------------+| function code 1B | data 0-252B |+------------------+-----------------------------+Reading one holding register at address 0 looks like this:
request PDU 03 0000 0001 function 03, start address 0, quantity 1response PDU 03 02 002A function 03, byte count 2, value 0x002A (42)Writing 42 to holding register 0 is 06 0000 002A, and the normal response echoes the same five bytes.
PDComm accepts a PDU as a hex string ("0300000001") or a byte array ([3,0,0,0,1]) and returns responses as arrays of decimal bytes ([3,2,0,42]). Never put an MBAP header, a unit address, a CRC or an LRC into a PDU: the transport adds and removes them.
The ADU wraps the PDU with addressing and error checking. The same read request on each transport:
| Transport | ADU layout | Maximum size | Bytes of the same request |
|---|---|---|---|
| Modbus TCP | 7-byte MBAP header + PDU | 260 bytes | 00 01 00 00 00 06 01 03 00 00 00 01 |
| RTU | 1-byte unit address + PDU + 2-byte CRC | 256 bytes | 01 03 00 00 00 01 84 0A |
| ASCII | : + hex characters (address, PDU, LRC) + CR LF |
513 characters | :010300000001FB + CR LF |
- Modbus TCP explains the MBAP header.
- Serial line: RTU and ASCII explains the RTU CRC and the ASCII LRC.
Function code categories
Section titled “Function code categories”Section 5 sorts function codes into three categories:
| Category | Range | Meaning |
|---|---|---|
| Public | Defined codes in 1–64, 73–99 and 111–127 | Defined and validated by the Modbus Organization. |
| User-defined | 65–72 and 100–110 | Free for a vendor to define, with no interoperability guarantee. |
| Reserved | Some other codes | Used by legacy products; don’t use them for new functions. |
Values of 128 and above are for exception responses: an exception response carries the request’s function code plus 0x80.
Function codes in PDComm
Section titled “Function codes in PDComm”PDComm supports these 19 public function codes. The capabilities command returns the same list in its functions field.
| Code (dec / hex) | Name | Spec | Example request PDU | PDComm limits |
|---|---|---|---|---|
| 1 / 0x01 | Read Coils | §6.1 | 0100000008 |
Quantity 1–2000 |
| 2 / 0x02 | Read Discrete Inputs | §6.2 | 0200000008 |
Quantity 1–2000 |
| 3 / 0x03 | Read Holding Registers | §6.3 | 0300000001 |
Quantity 1–125 |
| 4 / 0x04 | Read Input Registers | §6.4 | 0400000001 |
Quantity 1–125 |
| 5 / 0x05 | Write Single Coil | §6.5 | 050000FF00 |
Value FF00 (on) or 0000 (off) |
| 6 / 0x06 | Write Single Register | §6.6 | 060000002A |
|
| 7 / 0x07 | Read Exception Status | §6.7 | 07 |
Serial line only |
| 8 / 0x08 | Diagnostics | §6.8 | 0800001234 |
Serial line only; sub-functions below |
| 11 / 0x0B | Get Comm Event Counter | §6.9 | 0B |
Serial line only |
| 12 / 0x0C | Get Comm Event Log | §6.10 | 0C |
Serial line only; last 64 events |
| 15 / 0x0F | Write Multiple Coils | §6.11 | 0F0000000801A5 |
Quantity 1–1968 |
| 16 / 0x10 | Write Multiple Registers | §6.12 | 1000000001020009 |
Quantity 1–123 |
| 17 / 0x11 | Report Server ID | §6.13 | 11 |
Serial line only |
| 20 / 0x14 | Read File Record | §6.14 | 140706000100000001 |
File number 1 or higher, records 0–9999 |
| 21 / 0x15 | Write File Record | §6.15 | 1509060001000000010009 |
Checks every record range before writing any |
| 22 / 0x16 | Mask Write Register | §6.16 | 160000FF000055 |
Result = (current AND And_Mask) OR (Or_Mask AND NOT And_Mask) |
| 23 / 0x17 | Read/Write Multiple Registers | §6.17 | 170000000100000001020009 |
Read 1–125, write 1–121; writes before reading |
| 24 / 0x18 | Read FIFO Queue | §6.18 | 180000 |
Up to 31 values; reading doesn’t empty the queue |
| 43 / 0x2B | Read Device Identification (MEI 14) | §6.21 | 2B0E0100 |
Read codes 1 (basic) to 4 (individual) |
- Serial line only functions are the ones the specification restricts to serial lines. A PDComm TCP server answers them with exception 01, and a PDComm TCP client refuses to send them and returns the
Unsupportederror. - MEI 13 (CANopen General Reference, §6.20) is an opaque extension interface. The default server answers it with exception 01.
- User-defined codes also get exception 01 from the default server.
Diagnostics (function 08) sub-functions
Section titled “Diagnostics (function 08) sub-functions”A diagnostics request carries a two-byte sub-function code and two bytes of data. PDComm supports these 15 sub-functions:
| Sub-function (dec / hex) | Name | Request PDU | Response |
|---|---|---|---|
| 0 / 0x0000 | Return Query Data | 0800001234 |
Echoes the data. |
| 1 / 0x0001 | Restart Communications Option | 0800010000 |
Responds, then restarts and clears the counters. Data FF00 also clears the event log. |
| 2 / 0x0002 | Return Diagnostic Register | 0800020000 |
Diagnostic register value |
| 3 / 0x0003 | Change ASCII Input Delimiter | 0800030A00 |
Responds, then changes the ASCII end character. |
| 4 / 0x0004 | Force Listen Only Mode | 0800040000 |
No response; enters listen-only mode. |
| 10 / 0x000A | Clear Counters and Diagnostic Register | 08000A0000 |
Clears the counters and the diagnostic register. |
| 11 / 0x000B | Return Bus Message Count | 08000B0000 |
Messages seen on the bus |
| 12 / 0x000C | Return Bus Communication Error Count | 08000C0000 |
CRC and LRC errors |
| 13 / 0x000D | Return Bus Exception Error Count | 08000D0000 |
Exception responses sent |
| 14 / 0x000E | Return Server Message Count | 08000E0000 |
Messages addressed to this server |
| 15 / 0x000F | Return Server No Response Count | 08000F0000 |
Messages left unanswered |
| 16 / 0x0010 | Return Server NAK Count | 0800100000 |
NAKs |
| 17 / 0x0011 | Return Server Busy Count | 0800110000 |
Busy exceptions |
| 18 / 0x0012 | Return Bus Character Overrun Count | 0800120000 |
Character overruns |
| 20 / 0x0014 | Clear Overrun Counter and Flag | 0800140000 |
Clears the overrun counter and flag. |
A server in listen-only mode answers nothing. The only way out is sub-function 1 (Restart Communications Option), and even that request gets no response.
Exception responses
Section titled “Exception responses”When a server can’t process a request it sends a two-byte exception response:
request PDU 03 FFFF 0001 read 1 register at address 65535exception response 83 02 0x03 + 0x80, exception code 02Section 7 defines these exception codes:
| Code | Name | Meaning |
|---|---|---|
| 01 | Illegal Function | The server doesn’t support the function, or doesn’t allow it in its current state. |
| 02 | Illegal Data Address | The address, or the address plus quantity, doesn’t exist in the server. |
| 03 | Illegal Data Value | A value or length in the request is invalid. |
| 04 | Server Device Failure | An unrecoverable error occurred while processing the request. |
| 05 | Acknowledge | The server accepted a long-running request; poll for the result later. |
| 06 | Server Device Busy | The server is busy; send the request again later. |
| 08 | Memory Parity Error | The server found a parity error in file record memory. |
| 0A | Gateway Path Unavailable | The gateway has no path to the target. |
| 0B | Gateway Target Device Failed to Respond | The gateway got no response from the target device. |
An exception response is a normal Modbus response. In PDComm, a request or execute that receives one succeeds, and its result has "status":"exception". Connection failures, timeouts, invalid JSON and a connect without a license, by contrast, make the call fail: the C API returns PDCOMM_MODBUS_SERVICE_ERROR from pdcomm_modbus_call, and C++ and .NET throw.
{"ok":true,"result":{"response":[131,2],"source":"local","status":"exception"}}Exception responses lists when a PDComm server sends each one.
Local execution and wire requests
Section titled “Local execution and wire requests”PDComm processes the same PDU in two ways, told apart by the result’s source field:
| Command | source |
Processing |
|---|---|---|
execute |
local |
Runs against the endpoint’s own data model without any I/O. Use it to check server behavior. |
request |
wire |
A connected client sends the request to the peer and receives the response. |
A local result proves nothing about communication. Check a wire result to confirm you actually talked to a device.