1mod data_model; pub use data_model::{DataModel, DataStructure};
2
3use crate::common::{crc, exception::Exception, PacketError, RequestForm};
4
5
6#[derive(Debug)]
8pub struct ModbusSlave<const L1: usize, const L2: usize> {
9 modbus_id: u8,
15
16 holding_registers: DataModel<L1, u16>,
21
22 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 if len < 4 {
64 return Err(PacketError::TooShort(len));
65 }
66
67 crc::validate(packet)?;
69
70 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 0x03 => {
79 if self.holding_registers.is_empty() {
81 return Err(PacketError::Exeption(fc, Exception::IllegalFunction));
82 }
83
84 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 if registers_count == 0 {
94 return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
95 }
96
97 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 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 0x04 => {
115 if self.input_registers.is_empty() {
117 return Err(PacketError::Exeption(fc, Exception::IllegalFunction));
118 }
119
120 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 if registers_count == 0 {
130 return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
131 }
132
133 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 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 0x06 => {
151 if self.holding_registers.is_empty() {
153 return Err(PacketError::Exeption(fc, Exception::IllegalFunction));
154 }
155
156 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 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 0x10 => {
174 if self.holding_registers.is_empty() {
176 return Err(PacketError::Exeption(fc, Exception::IllegalFunction));
177 }
178
179 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 if len < 9 + bytes_count as usize {
190 return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
191 }
192
193 if bytes_count as u16 != registers_count.saturating_mul(2) {
195 return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
196 }
197
198 if registers_count == 0 {
200 return Err(PacketError::Exeption(fc, Exception::IllegalDataValue));
201 }
202
203 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 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 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 #[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}