-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmodbus.txt
125 lines (111 loc) · 6.14 KB
/
modbus.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
Modbus Notes:
-------------
Modbus Data Model
-----------------
Memory Block Data Type Host Access Peripheral Access
---------------------------------------------------------------
Coil Boolean R/W R/W
Discrete Input Boolean R R/W
Input Register Unsigned Word R R/W
Holding Register Unsigned Word R/W R/W
Addressing:
-----------
Modbus address space is 16 bits
Separate address spaces for each Memory Block type (like Harvard Architecture)
So address space is effectively 18 bits, but only certain data types can go
in certain regions. Specifically, the regions are assigned a "prefix" when
discussing the address space. We can use these prefixes directly as address
bits 17 and 16.
Memory Block Prefix Address Range
---------------------------------------
Coil 0 0x00000-0x0ffff
Discrete Input 1 0x10000-0x1ffff
Input Register 2 0x20000-0x2ffff
Holding Register 3 0x30000-0x3ffff
Modbus addresses are often confusingly written in decimal with an offset equal to 10,000*(prefix+1),
so e.g. address 10100 is coil number 100.
Protocol Data Unit (PDU)
------------------------
PDU defined as a function code followed by an associated set of data (cannot exceed 252 bytes).
The first byte of the PDU is always a function code (see below). The remaining PDU format is
specific to the function in question.
Function Codes:
---------------
A function code is like an operation in the packet - it tells the peripheral what the host wants
it to do with the following information. Modbus has several layers of compatibility. The bare
minimum function code set to implement to be considered compatible is the "Class 0 Codes".
Additional funtion codes (in higher number classes) can be optionally implemented for greater
functionality.
Class Code Desc
----------------
0 3 Read multiple registers
Request PDU: | Func Code (1 byte) = 3 | Start Addr (2 bytes) | Qty Regs (2 bytes) |
Response PDU: | Func Code (1 byte) = 3 | Byte Count (1 byte) | Reg Vals (2 bytes for each reg = 2*"Qty Regs") |
Error PDU: | Error Code (1 byte) = Func Code + 0x80 | Exception Code (1 byte) |
0 16 Write multiple registers
1 1 Read coils
Request PDU: | Func Code (1 byte) = 1 | Start Addr (2 bytes) | Qty Coils (2 bytes) |
Response PDU: | Func Code (1 byte) = 1 | Byte Count (1 byte) | Coil Vals (2 bytes for each coil = 2*"Qty Coils") |
Error PDU: | Error Code (1 byte) = Func Code + 0x80 | Exception Code (1 byte) |
"Qty Coils" can be 1 to 2000.
1 2 Read discrete inputs
1 4 Read input registers
1 5 Write single coil
1 6 Write single register
Request PDU: | Func Code (1 byte) | Reg Addr (2 bytes) | Reg Val (2 byte) |
Response PDU: | Func Code (1 byte) | Reg Addr (2 bytes) | Reg Val (2 byte) |
Error PDU: | Error Code (1 byte) = Func Code + 0x80 | Exception Code (1 byte) |
1 7 Read exception status (serial-only)
2 15 Write multiple coils
2 20 Read file record
2 21 Write file record
2 22 Mask write register
2 23 Read/Write multiple registers
2 24 Read FIFO
Exceptions:
-----------
A peripheral is required to reply with an exception to indicate a variety of failure conditions.
An exception packet looks a lot like a normal reply but with the MSb in the function code asserted
(0x80 | function_code) followed by a single byte exception code rather than the normal data that
would follow the function code.
Modbus over UDP:
----------------
Modbus is carried over UDP in the datagram packet payload as an "Application Data Unit" (ADU) which
carries a PDU as well as some context in a prepended header. Fun fact: the header has a name: "Modbus
Application Protocol" (MBAP).
| IP Header | Datagram |
_____________/\_________
/ \
| UDP Header | Data (ADU) |
________________/\________________________
/ \
| MBAP Header (7 bytes) | PDU (1-253 bytes) |
________/\______________________________________________________________________
/ \
| Xact ID (2 bytes) | Protocol ID (2 bytes) | Length (2 bytes) | Unit ID (1 byte) |
Header Elements:
----------------
Xact ID: Transaction ID used to associate request and response. A reply should copy this field
unmodified from the associated request.
Protocol ID: Can leave as 0 or implement more elaborate protocol parsing.
Length: The length of the remainder of the packet (a bit redundant with UDP payload length)
Unit ID: An ID number for the destination device. Typically left as 0 for TCP/UDP, but can be used for
a "modbus hub" that makes multiple Modbus-serial devices available over TCP/UDP.
Modbus over Serial:
-------------------
Modbus-RTU:
-----------
Simplest encoding type. Frames delimited by time intervals.
| Slv Addr (1 byte) | PDU (1-253 bytes) | CRC (2 byte) |
Modbus-ASCII:
-------------
Frames delimited by reserved characters (':' and CR/LF).
Every byte is an ASCII-encoded char representing a nibble in hex.
PDU is also encoded as hex-ASCII, so is 2x the normal length (in bytes).
LRC = "Longitudinal Redundancy Check" also transmitted as two bytes in hex-ASCII
| Start byte ":" = 0x3a | Station Address (2 bytes, hex-ASCII) | PDU (normal PDU len x2) | LRC (2 bytes) | End (CR/LF) |
Test:
val = client.read_holding_registers(0, count=1) # function code 3
| Slv Addr (1 byte) | PDU (1-253 bytes) | CRC (2 byte) |
| Slv Addr (1 byte) = 1? | Func Code (1 byte) = 3 | Start Addr (2 bytes) = 0,0 | Qty Regs (2 bytes) = 0,1 | CRC (2 byte) |
1, 3, 0, 0, 0, 1, crc_lo, crc_hi