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                // Register address overflowed
93                let end_register: u16 = match start_register.checked_add(registers_count) {
94                    Some(v) => v,
95                    None => return Err(PacketError::Exeption(fc, Exception::IllegalDataAddress)),
96                };
97
98                // All register addresses must be valid
99                for adr in start_register..=end_register {
100                    if let None = self.holding_registers.find_index(adr) {
101                        return Err(PacketError::Exeption(fc, Exception::IllegalDataAddress));
102                    }
103                }
104
105                Ok(RequestForm::ReadHoldingRegisters { start_register, registers_count })
106            },
107
108            // Process read input registers
109            0x04 => {
110                // If the input registers have zero capacity, the request is treated as not supported.
111                if self.input_registers.is_empty() {
112                    return Err(PacketError::Exeption(fc, Exception::IllegalFunction));
113                }
114
115                // Required length
116                if len < 8 {
117                    return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
118                }
119                
120                let start_register: u16 = ((packet[2] as u16) << 8) | (packet[3] as u16);
121                let registers_count: u16 = ((packet[4] as u16) << 8) | (packet[5] as u16);
122
123                // Register address overflowed
124                let end_register: u16 = match start_register.checked_add(registers_count) {
125                    Some(v) => v,
126                    None => return Err(PacketError::Exeption(fc, Exception::IllegalDataAddress)),
127                };
128
129                // All register addresses must be valid
130                for adr in start_register..=end_register {
131                    if let None = self.input_registers.find_index(adr) {
132                        return Err(PacketError::Exeption(fc, Exception::IllegalDataAddress));
133                    }
134                }
135
136                Ok(RequestForm::ReadInputRegisters { start_register, registers_count })
137            },
138
139            // Process write single register
140            0x06 => {
141                // If the holding registers have zero capacity, the request is treated as not supported.
142                if self.holding_registers.is_empty() {
143                    return Err(PacketError::Exeption(fc, Exception::IllegalFunction));
144                }
145
146                // Required length
147                if len < 8 {
148                    return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
149                }
150                
151                let register_address: u16 = ((packet[2] as u16) << 8) | (packet[3] as u16);
152                let data_to_write: u16 = ((packet[4] as u16) << 8) | (packet[5] as u16);
153
154                // Register address must be valid
155                if let None = self.holding_registers.find_index(register_address) {
156                    return Err(PacketError::Exeption(fc, Exception::IllegalDataAddress));
157                }
158
159                Ok(RequestForm::WriteSingleRegister { register_address, data_to_write })
160            },
161
162            // Process write multiple registers
163            0x10 => {
164                // If the holding registers have zero capacity, the request is treated as not supported.
165                if self.holding_registers.is_empty() {
166                    return Err(PacketError::Exeption(fc, Exception::IllegalFunction));
167                }
168                
169                // Minimum required length
170                if len < 9 {
171                    return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
172                }
173
174                let start_register: u16 = ((packet[2] as u16) << 8) | (packet[3] as u16);
175                let registers_count: u16 = ((packet[4] as u16) << 8) | (packet[5] as u16);
176                let bytes_count: u8 = packet[6];
177
178                // Required length
179                if len < 9 + bytes_count as usize {
180                    return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
181                }
182
183                // Bytes count must be double of the registers count
184                if bytes_count as u16 != registers_count.saturating_mul(2) {
185                    return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
186                }
187
188                // Register address overflowed
189                let end_register: u16 = match start_register.checked_add(registers_count) {
190                    Some(v) => v,
191                    None => return Err(PacketError::Exeption(fc, Exception::IllegalDataAddress)),
192                };
193
194                // All register addresses must be valid
195                for adr in start_register..=end_register {
196                    if let None = self.holding_registers.find_index(adr) {
197                        return Err(PacketError::Exeption(fc, Exception::IllegalDataAddress));
198                    }
199                }
200
201                // All data to write
202                for i in 0..registers_count as usize {
203                    word_buffer[i] = ((packet[7 + (i * 2) + 0] as u16) << 8) | (packet[7 + (i * 2) + 1] as u16);
204                }
205
206                Ok(RequestForm::WriteMultipleRegisters { start_register, datas_to_write: &word_buffer[..registers_count as usize] })
207            },
208
209            // Process bypass packet
210            #[cfg(feature="bypass")]
211            0x45 => {
212                todo!()
213            },
214            _ => return Err(PacketError::Exeption(fc, Exception::IllegalFunction)),
215        }
216    }
217
218    pub fn build_exception_response_packet(&self, fc: u8, exception: Exception) -> [u8; 5] {
219        let mut result: [u8; 5] = [
220            self.modbus_id,
221            fc | 0x80,
222            exception.into(),
223            0x00,
224            0x00,
225        ];
226
227        let crc_bytes = crc::gen_bytes(&result[..3]);
228        result[3..5].copy_from_slice(&crc_bytes);
229
230        result
231    }
232}