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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//! Modbus protocol constants based on official specification
//!
//! These constants are derived from the official Modbus specification:
//! - Maximum PDU size: 253 bytes (inherited from RS485 ADU limit of 256 bytes)
//! - Register/coil limits are calculated to fit within the PDU size constraint
// ============================================================================
// Frame Size Constants
// ============================================================================
/// Modbus MBAP header length for TCP
/// Format: Transaction ID(2) + Protocol ID(2) + Length(2) + Unit ID(1) = 7 bytes
/// Note: Length field itself is not counted in MBAP_HEADER_LEN for frame parsing
pub const MBAP_HEADER_LEN: usize = 6;
/// Maximum PDU (Protocol Data Unit) size per Modbus specification
/// This is the fundamental limit inherited from RS485 implementation:
/// RS485 ADU (256 bytes) - Slave Address (1 byte) - CRC (2 bytes) = 253 bytes
pub const MAX_PDU_SIZE: usize = 253;
/// Maximum MBAP length field value (Unit ID + PDU)
/// Used for validating the Length field in MBAP header
/// = 1 (Unit ID) + 253 (Max PDU) = 254 bytes
pub const MAX_MBAP_LENGTH: usize = 1 + MAX_PDU_SIZE;
/// Response buffer size for receiving Modbus frames
///
/// Calculation:
/// - MBAP Header: 6 bytes (MBAP_HEADER_LEN)
/// - Max MBAP Length (Unit ID + PDU): 254 bytes (MAX_MBAP_LENGTH)
/// - Theoretical max frame: 6 + 254 = 260 bytes
/// - Buffer size: 512 bytes (provides safety margin)
pub const MODBUS_RESPONSE_BUFFER_SIZE: usize = 512;
// ============================================================================
// Register Operation Limits
// ============================================================================
/// Maximum number of registers for FC03/FC04 (Read Holding/Input Registers)
///
/// Calculation for response PDU:
/// - Function Code: 1 byte
/// - Byte Count: 1 byte
/// - Register Data: N × 2 bytes
/// - Total: 1 + 1 + (N × 2) ≤ 253
/// - Therefore: N ≤ (253 - 2) / 2 = 125.5 → 125 registers
pub const MAX_READ_REGISTERS: usize = 125;
/// Maximum number of registers for FC16 (Write Multiple Registers)
///
/// Calculation for request PDU:
/// - Function Code: 1 byte
/// - Starting Address: 2 bytes
/// - Quantity of Registers: 2 bytes
/// - Byte Count: 1 byte
/// - Register Values: N × 2 bytes
/// - Total: 1 + 2 + 2 + 1 + (N × 2) ≤ 253
/// - Therefore: N ≤ (253 - 6) / 2 = 123.5 → 123 registers
pub const MAX_WRITE_REGISTERS: usize = 123;
// ============================================================================
// Coil Operation Limits
// ============================================================================
/// Maximum number of coils for FC01/FC02 (Read Coils/Discrete Inputs)
///
/// Calculation for response PDU:
/// - Function Code: 1 byte
/// - Byte Count: 1 byte
/// - Coil Data: ceil(N / 8) bytes
/// - Total: 1 + 1 + ceil(N / 8) ≤ 253
/// - Therefore: ceil(N / 8) ≤ 251, N ≤ 251 × 8 = 2008
/// - Spec defines: N ≤ 2000 (rounded for practical use)
pub const MAX_READ_COILS: usize = 2000;
/// Maximum number of coils for FC15 (Write Multiple Coils)
///
/// Calculation for request PDU:
/// - Function Code: 1 byte
/// - Starting Address: 2 bytes
/// - Quantity of Outputs: 2 bytes
/// - Byte Count: 1 byte
/// - Coil Values: ceil(N / 8) bytes
/// - Total: 1 + 2 + 2 + 1 + ceil(N / 8) ≤ 253
/// - Therefore: ceil(N / 8) ≤ 247, N ≤ 247 × 8 = 1976
/// - Spec defines: N ≤ 1968 (0x7B0, conservative practical limit)
pub const MAX_WRITE_COILS: usize = 1968;
// ============================================================================
// Modbus Function Codes
// ============================================================================
/// Read Coils (FC01)
pub const FC_READ_COILS: u8 = 0x01;
/// Read Discrete Inputs (FC02)
pub const FC_READ_DISCRETE_INPUTS: u8 = 0x02;
/// Read Holding Registers (FC03)
pub const FC_READ_HOLDING_REGISTERS: u8 = 0x03;
/// Read Input Registers (FC04)
pub const FC_READ_INPUT_REGISTERS: u8 = 0x04;
/// Write Single Coil (FC05)
pub const FC_WRITE_SINGLE_COIL: u8 = 0x05;
/// Write Single Register (FC06)
pub const FC_WRITE_SINGLE_REGISTER: u8 = 0x06;
/// Write Multiple Coils (FC15)
pub const FC_WRITE_MULTIPLE_COILS: u8 = 0x0F;
/// Write Multiple Registers (FC16)
pub const FC_WRITE_MULTIPLE_REGISTERS: u8 = 0x10;
// ============================================================================
// Modbus Exception Codes
// ============================================================================
/// Illegal Function
pub const EXCEPTION_ILLEGAL_FUNCTION: u8 = 0x01;
/// Illegal Data Address
pub const EXCEPTION_ILLEGAL_DATA_ADDRESS: u8 = 0x02;
/// Illegal Data Value
pub const EXCEPTION_ILLEGAL_DATA_VALUE: u8 = 0x03;
/// Server Device Failure
pub const EXCEPTION_SERVER_DEVICE_FAILURE: u8 = 0x04;
/// Acknowledge
pub const EXCEPTION_ACKNOWLEDGE: u8 = 0x05;
/// Server Device Busy
pub const EXCEPTION_SERVER_DEVICE_BUSY: u8 = 0x06;
/// Memory Parity Error
pub const EXCEPTION_MEMORY_PARITY_ERROR: u8 = 0x08;
/// Gateway Path Unavailable
pub const EXCEPTION_GATEWAY_PATH_UNAVAILABLE: u8 = 0x0A;
/// Gateway Target Device Failed to Respond
pub const EXCEPTION_GATEWAY_TARGET_FAILED: u8 = 0x0B;