1use crate::functions::PublicModbusFunction;
2
3macro_rules! read_req {
8 ($name:ident, $fcode:expr, $entity:literal, $test:ident) => {
9 #[doc=concat!("The request structure to read ", $entity)]
10 #[doc=concat!("\n")]
11 #[derive(Debug, Clone, Copy, Hash, Default, PartialEq, Eq, PartialOrd, Ord)]
13 pub struct $name {
14 pub addr: u16,
15 pub quantity: u16,
16 }
17
18 impl $name {
19 pub const MODBUS_FUNCTION_CODE: PublicModbusFunction = $fcode;
21
22 #[doc=concat!("Create a new request to read quantity ", $entity)]
23 pub const fn new(addr: u16, quantity: u16) -> Self {
24 Self { addr, quantity }
25 }
26
27 pub fn from_data(
32 data: &[u8],
33 ) -> Result<(Self, &[u8]), $crate::ModbusSerializationError> {
34 if data.len() < 4 {
35 Err($crate::ModbusSerializationError::UnexpectedEOF {
36 expected: 4,
37 got: data.len(),
38 })
39 } else {
40 Ok(unsafe { Self::from_data_unchecked(data) })
41 }
42 }
43
44 pub unsafe fn from_data_unchecked(data: &[u8]) -> (Self, &[u8]) {
52 let (addr, data) = $crate::util::read_u16_unchecked(data);
53 let (quantity, data) = $crate::util::read_u16_unchecked(data);
54
55 (Self::new(addr, quantity), data)
56 }
57
58 pub fn into_data(self) -> [u8; 5] {
62 let addr = self.addr.to_be_bytes();
63 let quantity = self.quantity.to_be_bytes();
64 [Self::MODBUS_FUNCTION_CODE as u8, addr[0], addr[1], quantity[0], quantity[1]]
65 }
66
67 pub fn write_to_slice(
69 self,
70 out: &mut [u8],
71 ) -> Result<(), $crate::ModbusSerializationError> {
72 if out.len() < 5 {
73 return Err($crate::ModbusSerializationError::InsufficientBuffer {
74 expected: 5,
75 got: out.len(),
76 });
77 }
78
79 unsafe { self.write_to_slice_unchecked(out) };
80 Ok(())
81 }
82
83 pub unsafe fn write_to_slice_unchecked(self, out: &mut [u8]) {
88 out.get_unchecked_mut(0..5).copy_from_slice(&self.into_data());
89 }
90 }
91
92 #[cfg(test)]
93 mod $test {
94 use super::*;
95
96 #[test]
97 fn create() {
98 let req = $name {
99 addr: 10,
100 quantity: 20,
101 };
102
103 let req_new = $name::new(10, 20);
104
105 assert_eq!(req, req_new);
106 assert_eq!(req.addr, req_new.addr);
107 assert_eq!(req.quantity, req_new.quantity);
108 }
109
110 #[test]
111 fn from_data0() {
112 let data = [0, 10, 0, 20];
113 let (req, tail) = $name::from_data(&data).unwrap();
114
115 assert_eq!(req.addr, 10);
116 assert_eq!(req.quantity, 20);
117 assert!(tail.is_empty());
118 }
119
120 #[test]
121 fn from_data1() {
122 let data = [1, 10, 2, 20];
123 let (req, tail) = $name::from_data(&data).unwrap();
124
125 assert_eq!(req.addr, 266);
126 assert_eq!(req.quantity, 532);
127 assert!(tail.is_empty());
128 }
129
130 #[test]
131 fn from_data2() {
132 let data = [0, 255, 0, 255];
133 let (req, tail) = $name::from_data(&data).unwrap();
134
135 assert_eq!(req.addr, 255);
136 assert_eq!(req.quantity, 255);
137 assert!(tail.is_empty());
138 }
139
140 #[test]
141 fn from_data3() {
142 let data = [255, 0, 255, 0];
143 let (req, tail) = $name::from_data(&data).unwrap();
144
145 assert_eq!(req.addr, 65280);
146 assert_eq!(req.quantity, 65280);
147 assert!(tail.is_empty());
148 }
149
150 #[test]
151 fn from_data4() {
152 let data = [255, 255, 255, 255];
153 let (req, tail) = $name::from_data(&data).unwrap();
154
155 assert_eq!(req.addr, u16::MAX);
156 assert_eq!(req.quantity, u16::MAX);
157 assert!(tail.is_empty());
158 }
159
160 #[test]
161 fn from_data_unchecked0() {
162 let data = [0, 10, 0, 20];
163 let (req, tail) = $name::from_data(&data).unwrap();
164
165 assert_eq!(req.addr, 10);
166 assert_eq!(req.quantity, 20);
167 assert!(tail.is_empty());
168 }
169
170 #[test]
171 fn from_data_unchecked1() {
172 let data = [1, 10, 2, 20];
173 let (req, tail) = unsafe { $name::from_data_unchecked(&data) };
174
175 assert_eq!(req.addr, 266);
176 assert_eq!(req.quantity, 532);
177 assert!(tail.is_empty());
178 }
179
180 #[test]
181 fn from_data_unchecked2() {
182 let data = [0, 255, 0, 255];
183 let (req, tail) = unsafe { $name::from_data_unchecked(&data) };
184
185 assert_eq!(req.addr, 255);
186 assert_eq!(req.quantity, 255);
187 assert!(tail.is_empty());
188 }
189
190 #[test]
191 fn from_data_unchecked3() {
192 let data = [255, 0, 255, 0];
193 let (req, tail) = unsafe { $name::from_data_unchecked(&data) };
194
195 assert_eq!(req.addr, 65280);
196 assert_eq!(req.quantity, 65280);
197 assert!(tail.is_empty());
198 }
199
200 #[test]
201 fn from_data_unchecked4() {
202 let data = [255, 255, 255, 255];
203 let (req, tail) = unsafe { $name::from_data_unchecked(&data) };
204
205 assert_eq!(req.addr, u16::MAX);
206 assert_eq!(req.quantity, u16::MAX);
207 assert!(tail.is_empty());
208 }
209
210 #[test]
211 fn from_data_fail0() {
212 let data = [255, 255];
213 let res = $name::from_data(&data);
214 assert_eq!(
215 res.unwrap_err(),
216 $crate::ModbusSerializationError::UnexpectedEOF {
217 expected: 4,
218 got: 2
219 }
220 );
221 }
222
223 #[test]
224 fn from_data_fail1() {
225 let data = [];
226 let res = $name::from_data(&data);
227 assert_eq!(
228 res.unwrap_err(),
229 $crate::ModbusSerializationError::UnexpectedEOF {
230 expected: 4,
231 got: 0
232 }
233 );
234 }
235
236 #[test]
237 fn from_data_fail2() {
238 let data = [255, 255, 0];
239 let res = $name::from_data(&data);
240 assert_eq!(
241 res.unwrap_err(),
242 $crate::ModbusSerializationError::UnexpectedEOF {
243 expected: 4,
244 got: 3
245 }
246 );
247 }
248
249 #[test]
250 fn from_data_tail0() {
251 let data = [255, 255, 255, 255, 1, 2, 3, 4];
252 let (req, tail) = $name::from_data(&data).unwrap();
253
254 assert_eq!(req.addr, u16::MAX);
255 assert_eq!(req.quantity, u16::MAX);
256 assert_eq!(tail, &[1, 2, 3, 4]);
257 }
258
259 #[test]
260 fn from_data_tail1() {
261 let data = [255, 255, 255, 255, 1];
262 let (req, tail) = $name::from_data(&data).unwrap();
263
264 assert_eq!(req.addr, u16::MAX);
265 assert_eq!(req.quantity, u16::MAX);
266 assert_eq!(tail, &[1]);
267 }
268
269 #[test]
270 fn from_data_unchecked_tail0() {
271 let data = [255, 255, 255, 255, 1, 2, 3, 4];
272 let (req, tail) = unsafe { $name::from_data_unchecked(&data) };
273
274 assert_eq!(req.addr, u16::MAX);
275 assert_eq!(req.quantity, u16::MAX);
276 assert_eq!(tail, &[1, 2, 3, 4]);
277 }
278
279 #[test]
280 fn from_data_unchecked_tail1() {
281 let data = [255, 255, 255, 255, 1];
282 let (req, tail) = unsafe { $name::from_data_unchecked(&data) };
283
284 assert_eq!(req.addr, u16::MAX);
285 assert_eq!(req.quantity, u16::MAX);
286 assert_eq!(tail, &[1]);
287 }
288
289 #[test]
290 fn from_data_eq_from_data_unecked() {
291 let data = [255, 255, 255, 255];
292 let (req_unchecked, tail_unchecked) = unsafe { $name::from_data_unchecked(&data) };
293 let (req, tail) = $name::from_data(&data).unwrap();
294
295 assert_eq!(req.addr, u16::MAX);
296 assert_eq!(req.quantity, u16::MAX);
297
298 assert_eq!(req_unchecked.addr, u16::MAX);
299 assert_eq!(req_unchecked.quantity, u16::MAX);
300
301 assert_eq!(req.addr, req_unchecked.addr);
302 assert_eq!(req.quantity, req_unchecked.quantity);
303
304 assert!(tail.is_empty());
305 assert_eq!(tail, tail_unchecked);
306 }
307
308 #[test]
309 fn into_data0() {
310 let data = [255, 255, 255, 255];
311 let (req, _tail) = $name::from_data(&data).unwrap();
312 assert_eq!(req.addr, u16::MAX);
313 assert_eq!(req.quantity, u16::MAX);
314 assert_eq!(data, req.into_data()[1..]);
315 }
316
317 #[test]
318 fn into_data1() {
319 let data = [0, 255, 0, 255];
320 let (req, _tail) = $name::from_data(&data).unwrap();
321 assert_eq!(req.addr, 255);
322 assert_eq!(req.quantity, 255);
323 assert_eq!(data, req.into_data()[1..]);
324 }
325
326 #[test]
327 fn into_data2() {
328 let req = $name::new(10, 20);
329 assert_eq!(req.addr, 10);
330 assert_eq!(req.quantity, 20);
331 assert_eq!([0, 10, 0, 20], req.into_data()[1..]);
332 }
333
334 #[test]
335 fn write_to_slice0() {
336 let req = $name::new(10, 20);
337 let mut slice = [0; 5];
338
339 req.write_to_slice(&mut slice).unwrap();
340 assert_eq!(slice, [$name::MODBUS_FUNCTION_CODE as u8, 0, 10, 0, 20]);
341 }
342
343 #[test]
344 fn write_to_slice1() {
345 let req = $name::new(256, 255);
346 let mut slice = [0, 1, 2, 3, 4];
347
348 req.write_to_slice(&mut slice).unwrap();
349 assert_eq!(slice, [$name::MODBUS_FUNCTION_CODE as u8, 1, 0, 0, 255]);
350 }
351
352 #[test]
353 fn write_to_slice2() {
354 let req = $name::new(u16::MAX, u16::MAX);
355 let mut slice = [1, 1, 1, 1, 1, 0, 0, 0, 0];
356
357 req.write_to_slice(&mut slice).unwrap();
358 assert_eq!(
359 slice,
360 [$name::MODBUS_FUNCTION_CODE as u8, 255, 255, 255, 255, 0, 0, 0, 0]
361 );
362 }
363
364 #[test]
365 fn write_to_slice_fail0() {
366 let req = $name::new(u16::MAX, u16::MAX);
367 let mut slice = [1, 1, 1, 1];
368
369 let err = req.write_to_slice(&mut slice).unwrap_err();
370
371 assert_eq!(err, $crate::ModbusSerializationError::InsufficientBuffer { got: 4, expected: 5 });
372 }
373
374 #[test]
375 fn write_to_slice_fail1() {
376 let req = $name::new(u16::MAX, u16::MAX);
377 let mut slice = [];
378
379 let err = req.write_to_slice(&mut slice).unwrap_err();
380
381 assert_eq!(err, $crate::ModbusSerializationError::InsufficientBuffer { got: 0, expected: 5 });
382 }
383
384 #[test]
385 fn write_to_slice_eq_write_to_slice_unchecked() {
386 let req = $name::new(u16::MAX, u16::MAX);
387 let mut slice = [1,2,3,4,5];
388 let mut slice_unchecked = [1,2,3,4,5];
389
390 req.write_to_slice(&mut slice).unwrap();
391 unsafe { req.write_to_slice_unchecked(&mut slice_unchecked) };
392
393 assert_eq!(slice, slice_unchecked);
394 assert_eq!(slice, [$name::MODBUS_FUNCTION_CODE as u8, 255, 255, 255, 255]);
395 assert_eq!(slice, [$name::MODBUS_FUNCTION_CODE as u8, 255, 255, 255, 255]);
396 }
397 }
398 };
399}
400
401read_req!(ReadCoils, PublicModbusFunction::ReadCoils, "Coils", coils);
402read_req!(
403 ReadDiscreteInputs,
404 PublicModbusFunction::ReadDiscreteInputs,
405 "DiscreteInputs",
406 discrete_inputs
407);
408read_req!(
409 ReadHoldingRegisters,
410 PublicModbusFunction::ReadHoldingRegisters,
411 "HoldingRegisters",
412 holding_registers
413);
414read_req!(
415 ReadInputRegisters,
416 PublicModbusFunction::ReadInputRegisters,
417 "InputRegisters",
418 input_registers
419);