Modbus/TCP

All Data is MSB (so, e.g. 0x1234 is encoded as 0x12 0x34 in bytes).

This tis the general Modbus header for all requests and responses

Offset Count Description
0x0000 2 Request identifier to reliably connect the response back to the request
0x0002 2 Protocol identifier, 0 for Modbus
0x0004 2 Number of remaining bytes after this
0x0006 1 Unit identifier (0xFF if not used)
0x0007 1 Function code (usually but not in every case)

Error response

When an error occurs, the 8th bit in the response's function code is set to 1 (so, 128 or 0x80 is added / ORed) and and only an error code is added as data

Functions

Function 1: Read Coils

Function 2: Read Discrete Inputs

Function 3: Read Multiple Holding Registers

Request

Offset Count Description
0x0000 2 Request identifier to reliably connect the response back to the request
0x0002 2 Protocol identifier, 0 for Modbus
0x0004 2 Number of remaining bytes after this (here: 6)
0x0006 1 Unit identifier (0xFF if not used)
0x0007 1 Function code (here: 3)
0x0008 2 Start address to read from
0x000A 2 Number of words to read

E.g. request 1, reading 5 words from address 2000:

00 01 00 00 00 06 FF 03 07 D0 00 05
  • 00 01: Request identifier 1
  • 00 00: Modbus protocol
  • 00 06: 6 bytes come after this
  • FF: Nevermind the unit
  • 03: Function code 3 (Read Multiple)
  • 07 D0: Start at address 2000 (0x07D0)
  • 00 05: Read 5 words

You can post a request to a Modbus server via linux commands ncand xxd:

echo -n -e '\x00\x01\x00\x00\x00\x06\xFF\x03\x07\xD0\x00\x05' | nc -vv -q 0 192.168.0.1 502 | xxd -ps
  • echo: put the data to send on the pipe
    • -n: Do not terminate with a new-line
    • -e: Unescape the bytes
    • \x00...: The bytes to send in escaped string form
  • nc: Connect to the server and send the data from the pipe
    • -vv: Print verbose information about the connection
    • -q 0: Terminate the connection after 0 seconds after the data was received
    • 192.168.0.1: The Modbus server address
    • 502: The port the Modbus service is provided on (default is 502)
  • xxd: Convert the response to hex data
    • -ps: Output as simple hex without adrress and string repesentation

Response

Offset Count Description
0x0000 2 Request identifier (mirrored from the request)
0x0002 2 Protocol identifier, 0 for Modbus
0x0004 2 Number of remaining bytes after this
0x0006 1 Unit identifier (0xFF if not used)
0x0007 1 Function code (here: 3)
0x0008 1 Number of data bytes to follow in this response (maybe to split the response to multiple responses?)
0x0009 * The result data of the read, 2 bytes per word

E.g. from the request above

00 01 00 00 00 0d ff 03 0a 11 11 20 02 30 03 40 04 50 05
  • 00 01: Request identifier 1
  • 00 00: Modbus protocol
  • 00 0d: 13 bytes come after this
  • ff: The unit identifier 255 is returned
  • 03: The response is to function code 3
  • 0a: 10 data bytes following
  • 10 01: First word @2000 (0x07D0): 0x1001 = 4097
  • 20 02: Second word @2001 (0x07D1): 0x2002 = 8194
  • ...

Error codes:

  • 01: Function code not supported
  • 02: Invalid address range
  • 03: Invalid number of registers to read (123 max)
  • 04: Unable to read registers

Function 4: Read Input Register

Function 5: Write Single Coil

Function 6: Write Single Holding Register

Function 15: Write Multiple Coils

Function 16: Write Multiple Holding Registers

Request

Offset Count Description
0x0000 2 Request identifier to reliably connect the response back to the request
0x0002 2 Protocol identifier, 0 for Modbus
0x0004 2 Number of remaining bytes after this (here: 7 + WordCount * 2)
0x0006 1 Unit identifier (0xFF if not used)
0x0007 1 Function code (here: 16 = 0x10)
0x0008 2 Start address to write to
0x000A 2 Number of words to write
0x000C 1 Number of bytes to follow (WordCount * 2, maybe to split the request into multiple packages?)
0x000E * Word data, 2 bytes for each word

  E.g. request 1, reading 5 words from address 2000:

00 01 00 00 00 11 FF 10 07 D0 00 05 0A 11 01 22 02 33 03 44 04 55 05
  • 00 01: Request identifier 1
  • 00 00: Modbus protocol
  • 00 11: 0x11 = 17 bytes come after this
  • FF: Nevermind the unit
  • 10: Function code 16 (Write Multiple)
  • 07 D0: Start at address 2000 (0x07D0)
  • 00 05: 5 words to write
  • 0A: 10 data bytes to follow (2 * 5)
  • 11 01: First word @2000 (0x07D0): 0x1101 = 4353
  • 22 02: Second word @2001 (0x07D1): 0x2202 = 8706
  • ...

You can post a request to a Modbus server via linux commands ncand xxd:

echo -n -e '\x00\x01\x00\x00\x00\x11\xFF\x10\x07\xD0\x00\x05\x0A\x11\x01\x22\x02\x33\x03\x44\x04\x55\x05' | nc -vv -q 0 192.168.0.1 502 | xxd -ps
  • echo: put the data to send on the pipe
    • -n: Do not terminate with a new-line
    • -e: Unescape the bytes
    • \x00...: The bytes to send in escaped string form
  • nc: Connect to the server and send the data from the pipe
    • -vv: Print verbose information about the connection
    • -q 0: Terminate the connection after 0 seconds after the data was received
    • 192.168.0.1: The Modbus server address
    • 502: The port the Modbus service is provided on (default is 502)
  • xxd: Convert the response to hex data
    • -ps: Output as simple hex without adrress and string repesentation

Response

Offset Count Description
0x0000 2 Request identifier (mirrored from the request)
0x0002 2 Protocol identifier, 0 for Modbus
0x0004 2 Number of remaining bytes after this (here: 6)
0x0006 1 Unit identifier (0xFF if not used)
0x0007 1 Function code (here: 0x11 = 16)
0x0008 2 Address of the first write written
0x000A 2 The number of words written

E.g. from the request above

00 01 00 00 00 06 ff 10 07 d0 00 05
  • 00 01: Request identifier 1
  • 00 00: Modbus protocol
  • 00 0d: 13 bytes come after this
  • ff: The unit identifier 255 is returned
  • 10: The response is to function code 16
  • 07 d0: Write started at address 0x07D0 = 2000
  • 00 05: 5 words have been written

Error codes:

  • 01: Function code not supported
  • 02: Invalid address range
  • 03: Invalid number of registers to write (123 max)
  • 04: Unable to write registers

Function 20: Read File Record

Function 21: Write File Record

Function 22: Mask Write Register

Function 23: Read/Write Multiple Holding Registers

Function 24: Read FIFO Queue

Function 43: Read Device Identification

This page was last edited on 2025-09-18 12:44

Powered by Wiki|Docs

This page was last edited on 2025-09-18 12:44

Bjørn Singer
Private wiki!

Powered by Wiki|Docs