modbus_rtu/slave/
mod.rs

1mod data_model;     pub use data_model::{DataModel, DataStructure};
2
3use crate::common::{crc, exception::Exception, PacketError, RequestForm};
4
5
6/// Modbus Slave
7#[derive(Debug)]
8pub struct ModbusSlave<const L1: usize, const L2: usize> {
9    /// The Modbus slave ID.
10    ///
11    /// Valid Modbus IDs range from `1` to `247`. This crate also supports reserved IDs from `248` to `255`.
12    /// If the ID is set to `0`, the device will listen to all Modbus IDs and never respond.
13    ///
14    modbus_id: u8,
15
16    /// Holding registers.
17    ///
18    /// Read-write registers that can be accessed and modified by the Modbus master.
19    /// 
20    holding_registers: DataModel<L1, u16>,
21
22    /// Input registers.
23    ///
24    /// Read-only registers that can be accessed by the Modbus master.
25    /// 
26    input_registers: DataModel<L2, u16>,
27}
28
29
30impl<'a, const L1: usize, const L2: usize> ModbusSlave<L1, L2> {
31    pub fn new(modbus_id: u8, holding_registers: DataModel<L1, u16>, input_registers: DataModel<L2, u16>) -> ModbusSlave<L1, L2> {
32        ModbusSlave { modbus_id, holding_registers, input_registers }
33    }
34
35    pub fn get_modbus_id(&self) -> u8 {
36        self.modbus_id
37    }
38
39    pub fn set_modbus_id(&mut self, modbus_id: u8) {
40        self.modbus_id = modbus_id;
41    }
42
43    pub fn get_holding_registers(&self) -> &DataModel<L1, u16> {
44        &self.holding_registers
45    }
46
47    pub fn get_holding_registers_mut(&mut self) -> &mut DataModel<L1, u16> {
48        &mut self.holding_registers
49    }
50
51    pub fn get_input_registers(&self) -> &DataModel<L2, u16> {
52        &self.input_registers
53    }
54
55    pub fn get_input_registers_mut(&mut self) -> &mut DataModel<L2, u16> {
56        &mut self.input_registers
57    }
58
59    pub fn analyze_packet(&self, packet: &[u8], word_buffer: &'a mut [u16]) -> Result<RequestForm<'a>, PacketError> {
60        let len = packet.len();
61
62        // Packet too short
63        if len < 4 {
64            return Err(PacketError::TooShort(len));
65        }
66
67        // Validate CRC bytes
68        crc::validate(packet)?;
69
70        // Check modbus ID
71        if (self.modbus_id != 0x00) && (self.modbus_id != packet[0]) {
72            return Err(PacketError::NotMyId(packet[0]));
73        }
74
75        let fc  = packet[1];
76        match fc {
77            // Process read holding registers
78            0x03 => {
79                // If the holding registers have zero capacity, the request is treated as not supported.
80                if self.holding_registers.is_empty() {
81                    return Err(PacketError::Exeption(fc, Exception::IllegalFunction));
82                }
83
84                // Required length
85                if len < 8 {
86                    return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
87                }
88
89                let start_register: u16 = ((packet[2] as u16) << 8) | (packet[3] as u16);
90                let registers_count: u16 = ((packet[4] as u16) << 8) | (packet[5] as u16);
91
92                // Registers count should not have be 0.
93                if registers_count == 0 {
94                    return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
95                }
96
97                // Register address overflowed
98                let end_register: u16 = match start_register.checked_add(registers_count - 1) {
99                    Some(v) => v,
100                    None => return Err(PacketError::Exeption(fc, Exception::IllegalDataAddress)),
101                };
102
103                // All register addresses must be valid
104                for adr in start_register..=end_register {
105                    if let None = self.holding_registers.find_index(adr) {
106                        return Err(PacketError::Exeption(fc, Exception::IllegalDataAddress));
107                    }
108                }
109
110                Ok(RequestForm::ReadHoldingRegisters { start_register, registers_count })
111            },
112
113            // Process read input registers
114            0x04 => {
115                // If the input registers have zero capacity, the request is treated as not supported.
116                if self.input_registers.is_empty() {
117                    return Err(PacketError::Exeption(fc, Exception::IllegalFunction));
118                }
119
120                // Required length
121                if len < 8 {
122                    return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
123                }
124                
125                let start_register: u16 = ((packet[2] as u16) << 8) | (packet[3] as u16);
126                let registers_count: u16 = ((packet[4] as u16) << 8) | (packet[5] as u16);
127
128                // Registers count should not have be 0.
129                if registers_count == 0 {
130                    return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
131                }
132
133                // Register address overflowed
134                let end_register: u16 = match start_register.checked_add(registers_count - 1) {
135                    Some(v) => v,
136                    None => return Err(PacketError::Exeption(fc, Exception::IllegalDataAddress)),
137                };
138
139                // All register addresses must be valid
140                for adr in start_register..=end_register {
141                    if let None = self.input_registers.find_index(adr) {
142                        return Err(PacketError::Exeption(fc, Exception::IllegalDataAddress));
143                    }
144                }
145
146                Ok(RequestForm::ReadInputRegisters { start_register, registers_count })
147            },
148
149            // Process write single register
150            0x06 => {
151                // If the holding registers have zero capacity, the request is treated as not supported.
152                if self.holding_registers.is_empty() {
153                    return Err(PacketError::Exeption(fc, Exception::IllegalFunction));
154                }
155
156                // Required length
157                if len < 8 {
158                    return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
159                }
160                
161                let register_address: u16 = ((packet[2] as u16) << 8) | (packet[3] as u16);
162                let data_to_write: u16 = ((packet[4] as u16) << 8) | (packet[5] as u16);
163
164                // Register address must be valid
165                if let None = self.holding_registers.find_index(register_address) {
166                    return Err(PacketError::Exeption(fc, Exception::IllegalDataAddress));
167                }
168
169                Ok(RequestForm::WriteSingleRegister { register_address, data_to_write })
170            },
171
172            // Process write multiple registers
173            0x10 => {
174                // If the holding registers have zero capacity, the request is treated as not supported.
175                if self.holding_registers.is_empty() {
176                    return Err(PacketError::Exeption(fc, Exception::IllegalFunction));
177                }
178                
179                // Minimum required length
180                if len < 9 {
181                    return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
182                }
183
184                let start_register: u16 = ((packet[2] as u16) << 8) | (packet[3] as u16);
185                let registers_count: u16 = ((packet[4] as u16) << 8) | (packet[5] as u16);
186                let bytes_count: u8 = packet[6];
187
188                // Required length
189                if len < 9 + bytes_count as usize {
190                    return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
191                }
192
193                // Bytes count must be double of the registers count
194                if bytes_count as u16 != registers_count.saturating_mul(2) {
195                    return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
196                }
197
198                // Registers count should not have be 0.
199                if registers_count == 0 {
200                    return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
201                }
202
203                // Register address overflowed
204                let end_register: u16 = match start_register.checked_add(registers_count - 1) {
205                    Some(v) => v,
206                    None => return Err(PacketError::Exeption(fc, Exception::IllegalDataAddress)),
207                };
208
209                // All register addresses must be valid
210                for adr in start_register..=end_register {
211                    if let None = self.holding_registers.find_index(adr) {
212                        return Err(PacketError::Exeption(fc, Exception::IllegalDataAddress));
213                    }
214                }
215
216                // All data to write
217                for i in 0..registers_count as usize {
218                    word_buffer[i] = ((packet[7 + (i * 2) + 0] as u16) << 8) | (packet[7 + (i * 2) + 1] as u16);
219                }
220
221                Ok(RequestForm::WriteMultipleRegisters { start_register, data_to_write: &word_buffer[..registers_count as usize] })
222            },
223
224            // Process bypass packet
225            #[cfg(feature="bypass")]
226            0x45 => {
227                todo!()
228            },
229            _ => return Err(PacketError::Exeption(fc, Exception::IllegalFunction)),
230        }
231    }
232
233    pub fn build_exception_response_packet(&self, fc: u8, exception: Exception) -> [u8; 5] {
234        let mut result: [u8; 5] = [
235            self.modbus_id,
236            fc | 0x80,
237            exception.into(),
238            0x00,
239            0x00,
240        ];
241
242        let crc_bytes = crc::gen_bytes(&result[..3]);
243        result[3..5].copy_from_slice(&crc_bytes);
244
245        result
246    }
247}