1use crate::{error::*, frame::*};
5use byteorder::{BigEndian, ByteOrder};
6
7pub mod rtu;
8pub mod tcp;
9
10#[cfg_attr(all(feature = "defmt", target_os = "none"), derive(defmt::Format))]
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum DecoderType {
14 Request,
15 Response,
16}
17
18type Result<T> = core::result::Result<T, Error>;
19
20impl TryFrom<u8> for Exception {
21 type Error = Error;
22
23 fn try_from(code: u8) -> Result<Self> {
24 let ex = match code {
25 0x01 => Self::IllegalFunction,
26 0x02 => Self::IllegalDataAddress,
27 0x03 => Self::IllegalDataValue,
28 0x04 => Self::ServerDeviceFailure,
29 0x05 => Self::Acknowledge,
30 0x06 => Self::ServerDeviceBusy,
31 0x08 => Self::MemoryParityError,
32 0x0A => Self::GatewayPathUnavailable,
33 0x0B => Self::GatewayTargetDevice,
34 _ => {
35 return Err(Error::ExceptionCode(code));
36 }
37 };
38 Ok(ex)
39 }
40}
41
42impl From<ExceptionResponse> for [u8; 2] {
43 fn from(ex: ExceptionResponse) -> [u8; 2] {
44 let data = &mut [0; 2];
45 let fn_code: u8 = ex.function.value();
46 debug_assert!(fn_code < 0x80);
47 data[0] = fn_code + 0x80;
48 data[1] = ex.exception as u8;
49 *data
50 }
51}
52
53impl TryFrom<&[u8]> for ExceptionResponse {
54 type Error = Error;
55
56 fn try_from(bytes: &[u8]) -> Result<Self> {
57 if bytes.is_empty() {
58 return Err(Error::BufferSize);
59 }
60 let fn_err_code = bytes[0];
61 if fn_err_code < 0x80 {
62 return Err(Error::ExceptionFnCode(fn_err_code));
63 }
64 let function = FunctionCode::new(fn_err_code - 0x80);
65 let exception = Exception::try_from(bytes[1])?;
66 Ok(ExceptionResponse {
67 function,
68 exception,
69 })
70 }
71}
72
73impl<'r> TryFrom<&'r [u8]> for Request<'r> {
74 type Error = Error;
75
76 fn try_from(bytes: &'r [u8]) -> Result<Self> {
77 use FunctionCode as F;
78
79 if bytes.is_empty() {
80 return Err(Error::BufferSize);
81 }
82
83 let fn_code = bytes[0];
84
85 if bytes.len() < min_request_pdu_len(FunctionCode::new(fn_code)) {
86 return Err(Error::BufferSize);
87 }
88
89 let req = match FunctionCode::new(fn_code) {
90 F::ReadCoils
91 | F::ReadDiscreteInputs
92 | F::ReadInputRegisters
93 | F::ReadHoldingRegisters
94 | F::WriteSingleRegister => {
95 let addr = BigEndian::read_u16(&bytes[1..3]);
96 let quantity = BigEndian::read_u16(&bytes[3..5]);
97
98 match FunctionCode::new(fn_code) {
99 F::ReadCoils => Self::ReadCoils(addr, quantity),
100 F::ReadDiscreteInputs => Self::ReadDiscreteInputs(addr, quantity),
101 F::ReadInputRegisters => Self::ReadInputRegisters(addr, quantity),
102 F::ReadHoldingRegisters => Self::ReadHoldingRegisters(addr, quantity),
103 F::WriteSingleRegister => Self::WriteSingleRegister(addr, quantity),
104 _ => unreachable!(),
105 }
106 }
107 F::WriteSingleCoil => Self::WriteSingleCoil(
108 BigEndian::read_u16(&bytes[1..3]),
109 u16_coil_to_bool(BigEndian::read_u16(&bytes[3..5]))?,
110 ),
111 F::WriteMultipleCoils => {
112 let address = BigEndian::read_u16(&bytes[1..3]);
113 let quantity = BigEndian::read_u16(&bytes[3..5]) as usize;
114 let byte_count = bytes[5];
115 if bytes.len() < (6 + byte_count as usize) {
116 return Err(Error::ByteCount(byte_count));
117 }
118 let data = &bytes[6..];
119 let coils = Coils { data, quantity };
120 Self::WriteMultipleCoils(address, coils)
121 }
122 F::WriteMultipleRegisters => {
123 let address = BigEndian::read_u16(&bytes[1..3]);
124 let quantity = BigEndian::read_u16(&bytes[3..5]) as usize;
125 let byte_count = bytes[5];
126 if bytes.len() < (6 + byte_count as usize) {
127 return Err(Error::ByteCount(byte_count));
128 }
129 let data = Data {
130 quantity,
131 data: &bytes[6..6 + byte_count as usize],
132 };
133 Self::WriteMultipleRegisters(address, data)
134 }
135 F::ReadWriteMultipleRegisters => {
136 let read_address = BigEndian::read_u16(&bytes[1..3]);
137 let read_quantity = BigEndian::read_u16(&bytes[3..5]);
138 let write_address = BigEndian::read_u16(&bytes[5..7]);
139 let write_quantity = BigEndian::read_u16(&bytes[7..9]) as usize;
140 let write_count = bytes[9];
141 if bytes.len() < (10 + write_count as usize) {
142 return Err(Error::ByteCount(write_count));
143 }
144 let data = Data {
145 quantity: write_quantity,
146 data: &bytes[10..10 + write_count as usize],
147 };
148 Self::ReadWriteMultipleRegisters(read_address, read_quantity, write_address, data)
149 }
150 _ => match fn_code {
151 fn_code if fn_code < 0x80 => {
152 Self::Custom(FunctionCode::Custom(fn_code), &bytes[1..])
153 }
154 _ => return Err(Error::FnCode(fn_code)),
155 },
156 };
157 Ok(req)
158 }
159}
160
161impl<'r> TryFrom<&'r [u8]> for Response<'r> {
162 type Error = Error;
163
164 fn try_from(bytes: &'r [u8]) -> Result<Self> {
165 use FunctionCode as F;
166 if bytes.is_empty() {
167 return Err(Error::BufferSize);
168 }
169 let fn_code = bytes[0];
170 if bytes.len() < min_response_pdu_len(FunctionCode::new(fn_code)) {
171 return Err(Error::BufferSize);
172 }
173 let rsp = match FunctionCode::new(fn_code) {
174 F::ReadCoils | FunctionCode::ReadDiscreteInputs => {
175 let byte_count = bytes[1] as usize;
176 if byte_count + 2 > bytes.len() {
177 return Err(Error::BufferSize);
178 }
179 let data = &bytes[2..byte_count + 2];
180 let quantity = byte_count * 8;
183
184 match FunctionCode::new(fn_code) {
185 FunctionCode::ReadCoils => Self::ReadCoils(Coils { data, quantity }),
186 FunctionCode::ReadDiscreteInputs => {
187 Self::ReadDiscreteInputs(Coils { data, quantity })
188 }
189 _ => unreachable!(),
190 }
191 }
192 F::WriteSingleCoil => Self::WriteSingleCoil(BigEndian::read_u16(&bytes[1..])),
193
194 F::WriteMultipleCoils | F::WriteSingleRegister | F::WriteMultipleRegisters => {
195 let addr = BigEndian::read_u16(&bytes[1..]);
196 let payload = BigEndian::read_u16(&bytes[3..]);
197 match FunctionCode::new(fn_code) {
198 F::WriteMultipleCoils => Self::WriteMultipleCoils(addr, payload),
199 F::WriteSingleRegister => Self::WriteSingleRegister(addr, payload),
200 F::WriteMultipleRegisters => Self::WriteMultipleRegisters(addr, payload),
201 _ => unreachable!(),
202 }
203 }
204 F::ReadInputRegisters | F::ReadHoldingRegisters | F::ReadWriteMultipleRegisters => {
205 let byte_count = bytes[1] as usize;
206 let quantity = byte_count / 2;
207 if byte_count + 2 > bytes.len() {
208 return Err(Error::BufferSize);
209 }
210 let data = &bytes[2..2 + byte_count];
211 let data = Data { data, quantity };
212
213 match FunctionCode::new(fn_code) {
214 F::ReadInputRegisters => Self::ReadInputRegisters(data),
215 F::ReadHoldingRegisters => Self::ReadHoldingRegisters(data),
216 F::ReadWriteMultipleRegisters => Self::ReadWriteMultipleRegisters(data),
217 _ => unreachable!(),
218 }
219 }
220 _ => Self::Custom(FunctionCode::new(fn_code), &bytes[1..]),
221 };
222 Ok(rsp)
223 }
224}
225
226pub trait Encode {
228 fn encode(&self, buf: &mut [u8]) -> Result<usize>;
229}
230
231impl Encode for Request<'_> {
232 fn encode(&self, buf: &mut [u8]) -> Result<usize> {
233 if buf.len() < self.pdu_len() {
234 return Err(Error::BufferSize);
235 }
236 buf[0] = FunctionCode::from(*self).value();
237 match self {
238 Self::ReadCoils(address, payload)
239 | Self::ReadDiscreteInputs(address, payload)
240 | Self::ReadInputRegisters(address, payload)
241 | Self::ReadHoldingRegisters(address, payload)
242 | Self::WriteSingleRegister(address, payload) => {
243 BigEndian::write_u16(&mut buf[1..], *address);
244 BigEndian::write_u16(&mut buf[3..], *payload);
245 }
246 Self::WriteSingleCoil(address, state) => {
247 BigEndian::write_u16(&mut buf[1..], *address);
248 BigEndian::write_u16(&mut buf[3..], bool_to_u16_coil(*state));
249 }
250 Self::WriteMultipleCoils(address, coils) => {
251 BigEndian::write_u16(&mut buf[1..], *address);
252 let len = coils.len();
253 BigEndian::write_u16(&mut buf[3..], len as u16);
254 buf[5] = coils.packed_len() as u8;
255 coils.copy_to(&mut buf[6..]);
256 }
257 Self::WriteMultipleRegisters(address, words) => {
258 BigEndian::write_u16(&mut buf[1..], *address);
259 let len = words.len();
260 BigEndian::write_u16(&mut buf[3..], len as u16);
261 buf[5] = len as u8 * 2;
262 for (idx, byte) in words.data.iter().enumerate() {
263 buf[idx + 6] = *byte;
264 }
265 }
266 Self::ReadWriteMultipleRegisters(read_address, quantity, write_address, words) => {
267 BigEndian::write_u16(&mut buf[1..], *read_address);
268 BigEndian::write_u16(&mut buf[3..], *quantity);
269 BigEndian::write_u16(&mut buf[5..], *write_address);
270 let n = words.len();
271 BigEndian::write_u16(&mut buf[7..], n as u16);
272 buf[9] = n as u8 * 2;
273 for (idx, byte) in words.data.iter().enumerate() {
274 buf[idx + 10] = *byte;
275 }
276 }
277 Self::Custom(_, custom_data) => {
278 custom_data.iter().enumerate().for_each(|(idx, d)| {
279 buf[idx + 1] = *d;
280 });
281 }
282 #[cfg(feature = "rtu")]
283 _ => panic!(),
284 }
285 Ok(self.pdu_len())
286 }
287}
288
289impl Encode for Response<'_> {
290 fn encode(&self, buf: &mut [u8]) -> Result<usize> {
291 if buf.len() < self.pdu_len() {
292 return Err(Error::BufferSize);
293 }
294
295 buf[0] = FunctionCode::from(*self).value();
296 match self {
297 Self::ReadCoils(coils) | Self::ReadDiscreteInputs(coils) => {
298 buf[1] = coils.packed_len() as u8;
299 coils.copy_to(&mut buf[2..]);
300 }
301 Self::ReadInputRegisters(registers)
302 | Self::ReadHoldingRegisters(registers)
303 | Self::ReadWriteMultipleRegisters(registers) => {
304 buf[1] = (registers.len() * 2) as u8;
305 registers.copy_to(&mut buf[2..]);
306 }
307 Self::WriteSingleCoil(address) => {
308 BigEndian::write_u16(&mut buf[1..], *address);
309 }
310 Self::WriteMultipleCoils(address, payload)
311 | Self::WriteMultipleRegisters(address, payload)
312 | Self::WriteSingleRegister(address, payload) => {
313 BigEndian::write_u16(&mut buf[1..], *address);
314 BigEndian::write_u16(&mut buf[3..], *payload);
315 }
316 Self::Custom(_, custom_data) => {
317 for (idx, d) in custom_data.iter().enumerate() {
318 buf[idx + 1] = *d;
319 }
320 }
321 #[cfg(feature = "rtu")]
322 Self::ReadExceptionStatus(error_code) => {
323 buf[1] = *error_code;
324 }
325 #[cfg(feature = "rtu")]
326 _ => {
327 unimplemented!()
329 }
330 }
331 Ok(self.pdu_len())
332 }
333}
334
335impl Encode for RequestPdu<'_> {
336 fn encode(&self, buf: &mut [u8]) -> Result<usize> {
337 self.0.encode(buf)
338 }
339}
340
341impl Encode for ResponsePdu<'_> {
342 fn encode(&self, buf: &mut [u8]) -> Result<usize> {
343 if buf.is_empty() {
344 return Err(Error::BufferSize);
345 }
346 match self.0 {
347 Ok(res) => res.encode(buf),
348 Err(e) => e.encode(buf),
349 }
350 }
351}
352
353impl Encode for ExceptionResponse {
354 fn encode(&self, buf: &mut [u8]) -> Result<usize> {
355 if buf.is_empty() {
356 return Err(Error::BufferSize);
357 }
358 let [code, ex]: [u8; 2] = (*self).into();
359 buf[0] = code;
360 buf[1] = ex;
361 Ok(2)
362 }
363}
364
365const fn min_request_pdu_len(fn_code: FunctionCode) -> usize {
366 use FunctionCode as F;
367 match fn_code {
368 F::ReadCoils
369 | F::ReadDiscreteInputs
370 | F::ReadInputRegisters
371 | F::WriteSingleCoil
372 | F::ReadHoldingRegisters
373 | F::WriteSingleRegister => 5,
374 F::WriteMultipleCoils | F::WriteMultipleRegisters => 6,
375 F::ReadWriteMultipleRegisters => 10,
376 _ => 1,
377 }
378}
379
380const fn min_response_pdu_len(fn_code: FunctionCode) -> usize {
381 use FunctionCode as F;
382 match fn_code {
383 F::ReadCoils
384 | F::ReadDiscreteInputs
385 | F::ReadInputRegisters
386 | F::ReadHoldingRegisters
387 | F::ReadWriteMultipleRegisters => 2,
388 F::WriteSingleCoil => 3,
389 F::WriteMultipleCoils | F::WriteSingleRegister | F::WriteMultipleRegisters => 5,
390 _ => 1,
391 }
392}
393
394#[cfg(test)]
395mod tests {
396 use super::*;
397
398 #[test]
399 fn exception_response_into_bytes() {
400 let bytes: [u8; 2] = ExceptionResponse {
401 function: FunctionCode::new(0x03),
402 exception: Exception::IllegalDataAddress,
403 }
404 .into();
405 assert_eq!(bytes[0], 0x83);
406 assert_eq!(bytes[1], 0x02);
407 }
408
409 #[test]
410 fn exception_response_from_bytes() {
411 let data: &[u8] = &[0x79, 0x02];
412 assert!(ExceptionResponse::try_from(data).is_err());
413
414 let bytes: &[u8] = &[0x83, 0x02];
415 let rsp = ExceptionResponse::try_from(bytes).unwrap();
416 assert_eq!(
417 rsp,
418 ExceptionResponse {
419 function: FunctionCode::new(0x03),
420 exception: Exception::IllegalDataAddress,
421 }
422 );
423 }
424
425 #[test]
426 fn test_min_request_pdu_len() {
427 use FunctionCode::*;
428
429 assert_eq!(min_request_pdu_len(ReadCoils), 5);
430 assert_eq!(min_request_pdu_len(ReadDiscreteInputs), 5);
431 assert_eq!(min_request_pdu_len(ReadInputRegisters), 5);
432 assert_eq!(min_request_pdu_len(WriteSingleCoil), 5);
433 assert_eq!(min_request_pdu_len(ReadHoldingRegisters), 5);
434 assert_eq!(min_request_pdu_len(WriteSingleRegister), 5);
435 assert_eq!(min_request_pdu_len(WriteMultipleCoils), 6);
436 assert_eq!(min_request_pdu_len(WriteMultipleRegisters), 6);
437 assert_eq!(min_request_pdu_len(ReadWriteMultipleRegisters), 10);
438 }
439
440 #[test]
441 fn test_min_response_pdu_len() {
442 use FunctionCode::*;
443
444 assert_eq!(min_response_pdu_len(ReadCoils), 2);
445 assert_eq!(min_response_pdu_len(ReadDiscreteInputs), 2);
446 assert_eq!(min_response_pdu_len(ReadInputRegisters), 2);
447 assert_eq!(min_response_pdu_len(WriteSingleCoil), 3);
448 assert_eq!(min_response_pdu_len(ReadHoldingRegisters), 2);
449 assert_eq!(min_response_pdu_len(WriteSingleRegister), 5);
450 assert_eq!(min_response_pdu_len(WriteMultipleCoils), 5);
451 assert_eq!(min_response_pdu_len(WriteMultipleRegisters), 5);
452 assert_eq!(min_response_pdu_len(ReadWriteMultipleRegisters), 2);
453 }
454
455 mod serialize_requests {
456 use super::*;
457
458 #[test]
459 fn read_coils() {
460 let bytes = &mut [0; 4];
461 assert!(Request::ReadCoils(0x12, 4).encode(bytes).is_err());
462 let bytes = &mut [0; 5];
463 Request::ReadCoils(0x12, 4).encode(bytes).unwrap();
464 assert_eq!(bytes[0], 1);
465 assert_eq!(bytes[1], 0x00);
466 assert_eq!(bytes[2], 0x12);
467 assert_eq!(bytes[3], 0x00);
468 assert_eq!(bytes[4], 0x04);
469 }
470
471 #[test]
472 fn read_discrete_inputs() {
473 let bytes = &mut [0; 5];
474 Request::ReadDiscreteInputs(0x03, 19).encode(bytes).unwrap();
475 assert_eq!(bytes[0], 2);
476 assert_eq!(bytes[1], 0x00);
477 assert_eq!(bytes[2], 0x03);
478 assert_eq!(bytes[3], 0x00);
479 assert_eq!(bytes[4], 19);
480 }
481
482 #[test]
483 fn write_single_coil() {
484 let bytes = &mut [0; 5];
485 Request::WriteSingleCoil(0x1234, true)
486 .encode(bytes)
487 .unwrap();
488 assert_eq!(bytes[0], 5);
489 assert_eq!(bytes[1], 0x12);
490 assert_eq!(bytes[2], 0x34);
491 assert_eq!(bytes[3], 0xFF);
492 assert_eq!(bytes[4], 0x00);
493 }
494
495 #[test]
496 fn write_multiple_coils() {
497 let states = &[true, false, true, true];
498 let buf = &mut [0];
499 let bytes = &mut [0; 7];
500 Request::WriteMultipleCoils(0x3311, Coils::from_bools(states, buf).unwrap())
501 .encode(bytes)
502 .unwrap();
503 assert_eq!(bytes[0], 0x0F);
504 assert_eq!(bytes[1], 0x33);
505 assert_eq!(bytes[2], 0x11);
506 assert_eq!(bytes[3], 0x00);
507 assert_eq!(bytes[4], 0x04);
508 assert_eq!(bytes[5], 0x01);
509 assert_eq!(bytes[6], 0b_0000_1101);
510 }
511
512 #[test]
513 fn read_input_registers() {
514 let bytes = &mut [0; 5];
515 Request::ReadInputRegisters(0x09, 77).encode(bytes).unwrap();
516 assert_eq!(bytes[0], 4);
517 assert_eq!(bytes[1], 0x00);
518 assert_eq!(bytes[2], 0x09);
519 assert_eq!(bytes[3], 0x00);
520 assert_eq!(bytes[4], 0x4D);
521 }
522
523 #[test]
524 fn read_holding_registers() {
525 let bytes = &mut [0; 5];
526 Request::ReadHoldingRegisters(0x09, 77)
527 .encode(bytes)
528 .unwrap();
529 assert_eq!(bytes[0], 3);
530 assert_eq!(bytes[1], 0x00);
531 assert_eq!(bytes[2], 0x09);
532 assert_eq!(bytes[3], 0x00);
533 assert_eq!(bytes[4], 0x4D);
534 }
535
536 #[test]
537 fn write_single_register() {
538 let bytes = &mut [0; 5];
539 Request::WriteSingleRegister(0x07, 0xABCD)
540 .encode(bytes)
541 .unwrap();
542 assert_eq!(bytes[0], 6);
543 assert_eq!(bytes[1], 0x00);
544 assert_eq!(bytes[2], 0x07);
545 assert_eq!(bytes[3], 0xAB);
546 assert_eq!(bytes[4], 0xCD);
547 }
548
549 #[test]
550 fn write_multiple_registers() {
551 let buf = &mut [0; 4];
552 let bytes = &mut [0; 10];
553
554 Request::WriteMultipleRegisters(
555 0x06,
556 Data::from_words(&[0xABCD, 0xEF12], buf).unwrap(),
557 )
558 .encode(bytes)
559 .unwrap();
560
561 assert_eq!(bytes[0], 0x10);
563
564 assert_eq!(bytes[1], 0x00);
566 assert_eq!(bytes[2], 0x06);
567
568 assert_eq!(bytes[3], 0x00);
570 assert_eq!(bytes[4], 0x02);
571
572 assert_eq!(bytes[5], 0x04);
574
575 assert_eq!(bytes[6], 0xAB);
577 assert_eq!(bytes[7], 0xCD);
578 assert_eq!(bytes[8], 0xEF);
579 assert_eq!(bytes[9], 0x12);
580 }
581
582 #[test]
583 fn read_write_multiple_registers() {
584 let buf = &mut [0; 4];
585 let bytes = &mut [0; 14];
586 let data = Data::from_words(&[0xABCD, 0xEF12], buf).unwrap();
587 Request::ReadWriteMultipleRegisters(0x05, 51, 0x03, data)
588 .encode(bytes)
589 .unwrap();
590
591 assert_eq!(bytes[0], 0x17);
593
594 assert_eq!(bytes[1], 0x00);
596 assert_eq!(bytes[2], 0x05);
597
598 assert_eq!(bytes[3], 0x00);
600 assert_eq!(bytes[4], 0x33);
601
602 assert_eq!(bytes[5], 0x00);
604 assert_eq!(bytes[6], 0x03);
605
606 assert_eq!(bytes[7], 0x00);
608 assert_eq!(bytes[8], 0x02);
609
610 assert_eq!(bytes[9], 0x04);
612
613 assert_eq!(bytes[10], 0xAB);
615 assert_eq!(bytes[11], 0xCD);
616 assert_eq!(bytes[12], 0xEF);
617 assert_eq!(bytes[13], 0x12);
618 }
619
620 #[test]
621 fn custom() {
622 let bytes = &mut [0; 5];
623 Request::Custom(FunctionCode::Custom(0x55), &[0xCC, 0x88, 0xAA, 0xFF])
624 .encode(bytes)
625 .unwrap();
626 assert_eq!(bytes[0], 0x55);
627 assert_eq!(bytes[1], 0xCC);
628 assert_eq!(bytes[2], 0x88);
629 assert_eq!(bytes[3], 0xAA);
630 assert_eq!(bytes[4], 0xFF);
631 }
632 }
633
634 mod deserialize_requests {
635 use super::*;
636
637 #[test]
638 fn empty_request() {
639 let data: &[u8] = &[];
640 assert!(Request::try_from(data).is_err());
641 }
642
643 #[test]
644 fn read_coils() {
645 let data: &[u8] = &[0x01];
646 assert!(Request::try_from(data).is_err());
647 let data: &[u8] = &[0x01, 0x0, 0x0, 0x22];
648 assert!(Request::try_from(data).is_err());
649
650 let data: &[u8] = &[0x01, 0x00, 0x12, 0x0, 0x4];
651 let req = Request::try_from(data).unwrap();
652 assert_eq!(req, Request::ReadCoils(0x12, 4));
653 }
654
655 #[test]
656 fn read_discrete_inputs() {
657 let data: &[u8] = &[2, 0x00, 0x03, 0x00, 19];
658 let req = Request::try_from(data).unwrap();
659 assert_eq!(req, Request::ReadDiscreteInputs(0x03, 19));
660 }
661
662 #[test]
663 fn write_single_coil() {
664 let bytes: &[u8] = &[5, 0x12, 0x34, 0xFF, 0x00];
665 let req = Request::try_from(bytes).unwrap();
666 assert_eq!(req, Request::WriteSingleCoil(0x1234, true));
667 }
668
669 #[test]
670 fn write_multiple_coils() {
671 let data: &[u8] = &[0x0F, 0x33, 0x11, 0x00, 0x04, 0x02, 0b_0000_1101];
672 assert!(Request::try_from(data).is_err());
673
674 let data: &[u8] = &[
675 0x0F, 0x33, 0x11, 0x00, 0x04, 0x00, ];
677 assert!(Request::try_from(data).is_ok());
678
679 let bytes: &[u8] = &[0x0F, 0x33, 0x11, 0x00, 0x04, 0x01, 0b_0000_1101];
680 let req = Request::try_from(bytes).unwrap();
681 assert_eq!(
682 req,
683 Request::WriteMultipleCoils(
684 0x3311,
685 Coils {
686 quantity: 4,
687 data: &[0b1101]
688 }
689 )
690 );
691 }
692
693 #[test]
694 fn read_input_registers() {
695 let bytes: &[u8] = &[4, 0x00, 0x09, 0x00, 0x4D];
696 let req = Request::try_from(bytes).unwrap();
697 assert_eq!(req, Request::ReadInputRegisters(0x09, 77));
698 }
699
700 #[test]
701 fn read_holding_registers() {
702 let bytes: &[u8] = &[3, 0x00, 0x09, 0x00, 0x4D];
703 let req = Request::try_from(bytes).unwrap();
704 assert_eq!(req, Request::ReadHoldingRegisters(0x09, 77));
705 }
706
707 #[test]
708 fn write_single_register() {
709 let bytes: &[u8] = &[6, 0x00, 0x07, 0xAB, 0xCD];
710 let req = Request::try_from(bytes).unwrap();
711 assert_eq!(req, Request::WriteSingleRegister(0x07, 0xABCD));
712 }
713
714 #[test]
715 fn write_multiple_registers() {
716 let data: &[u8] = &[0x10, 0x00, 0x06, 0x00, 0x02, 0x05, 0xAB, 0xCD, 0xEF, 0x12];
717 assert!(Request::try_from(data).is_err());
718
719 let bytes: &[u8] = &[0x10, 0x00, 0x06, 0x00, 0x02, 0x04, 0xAB, 0xCD, 0xEF, 0x12];
720 let req = Request::try_from(bytes).unwrap();
721 assert_eq!(
722 req,
723 Request::WriteMultipleRegisters(
724 0x06,
725 Data {
726 quantity: 2,
727 data: &[0xAB, 0xCD, 0xEF, 0x12]
728 }
729 )
730 );
731 if let Request::WriteMultipleRegisters(_, data) = req {
732 assert_eq!(data.get(0), Some(0xABCD));
733 assert_eq!(data.get(1), Some(0xEF12));
734 } else {
735 unreachable!()
736 }
737 }
738
739 #[test]
740 fn read_write_multiple_registers() {
741 let data: &[u8] = &[
742 0x17, 0x00, 0x05, 0x00, 0x33, 0x00, 0x03, 0x00, 0x02, 0x05, 0xAB, 0xCD, 0xEF, 0x12,
743 ];
744 assert!(Request::try_from(data).is_err());
745 let bytes: &[u8] = &[
746 0x17, 0x00, 0x05, 0x00, 0x33, 0x00, 0x03, 0x00, 0x02, 0x04, 0xAB, 0xCD, 0xEF, 0x12,
747 ];
748 let req = Request::try_from(bytes).unwrap();
749 let data = Data {
750 quantity: 2,
751 data: &[0xAB, 0xCD, 0xEF, 0x12],
752 };
753 assert_eq!(
754 req,
755 Request::ReadWriteMultipleRegisters(0x05, 51, 0x03, data)
756 );
757 if let Request::ReadWriteMultipleRegisters(_, _, _, data) = req {
758 assert_eq!(data.get(0), Some(0xABCD));
759 assert_eq!(data.get(1), Some(0xEF12));
760 } else {
761 unreachable!()
762 }
763 }
764
765 #[test]
766 fn custom() {
767 let bytes: &[u8] = &[0x55, 0xCC, 0x88, 0xAA, 0xFF];
768 let req = Request::try_from(bytes).unwrap();
769 assert_eq!(
770 req,
771 Request::Custom(FunctionCode::Custom(0x55), &[0xCC, 0x88, 0xAA, 0xFF])
772 );
773 }
774 }
775
776 mod serialize_responses {
777 use super::*;
778
779 #[test]
780 fn read_coils() {
781 let buff: &mut [u8] = &mut [0];
782 let res = Response::ReadCoils(
783 Coils::from_bools(&[true, false, false, true, false], buff).unwrap(),
784 );
785 let bytes = &mut [0, 0];
786 assert!(res.encode(bytes).is_err());
787 let bytes = &mut [0, 0, 0];
788 res.encode(bytes).unwrap();
789 assert_eq!(bytes[0], 1);
790 assert_eq!(bytes[1], 1);
791 assert_eq!(bytes[2], 0b_0000_1001);
792 }
793
794 #[test]
795 fn read_discrete_inputs() {
796 let buff: &mut [u8] = &mut [0];
797 let res = Response::ReadDiscreteInputs(
798 Coils::from_bools(&[true, false, true, true], buff).unwrap(),
799 );
800 let bytes = &mut [0, 0, 0];
801 res.encode(bytes).unwrap();
802 assert_eq!(bytes[0], 2);
803 assert_eq!(bytes[1], 1);
804 assert_eq!(bytes[2], 0b_0000_1101);
805 }
806
807 #[test]
808 fn write_single_coil() {
809 let res = Response::WriteSingleCoil(0x33);
810 let bytes = &mut [0, 0, 0];
811 res.encode(bytes).unwrap();
812 assert_eq!(bytes[0], 5);
813 assert_eq!(bytes[1], 0x00);
814 assert_eq!(bytes[2], 0x33);
815 }
816
817 #[test]
818 fn write_multiple_coils() {
819 let res = Response::WriteMultipleCoils(0x3311, 5);
820 let bytes = &mut [0; 5];
821 res.encode(bytes).unwrap();
822 assert_eq!(bytes[0], 0x0F);
823 assert_eq!(bytes[1], 0x33);
824 assert_eq!(bytes[2], 0x11);
825 assert_eq!(bytes[3], 0x00);
826 assert_eq!(bytes[4], 0x05);
827 }
828
829 #[test]
830 fn read_input_registers() {
831 let buf: &mut [u8] = &mut [0; 6];
832 let res = Response::ReadInputRegisters(
833 Data::from_words(&[0xAA00, 0xCCBB, 0xEEDD], buf).unwrap(),
834 );
835 let bytes = &mut [0; 8];
836 res.encode(bytes).unwrap();
837 assert_eq!(bytes[0], 4);
838 assert_eq!(bytes[1], 0x06);
839 assert_eq!(bytes[2], 0xAA);
840 assert_eq!(bytes[3], 0x00);
841 assert_eq!(bytes[4], 0xCC);
842 assert_eq!(bytes[5], 0xBB);
843 assert_eq!(bytes[6], 0xEE);
844 assert_eq!(bytes[7], 0xDD);
845 }
846
847 #[test]
848 fn read_holding_registers() {
849 let buf: &mut [u8] = &mut [0; 4];
850 let res =
851 Response::ReadHoldingRegisters(Data::from_words(&[0xAA00, 0x1111], buf).unwrap());
852 let bytes = &mut [0; 6];
853 res.encode(bytes).unwrap();
854 assert_eq!(bytes[0], 3);
855 assert_eq!(bytes[1], 0x04);
856 assert_eq!(bytes[2], 0xAA);
857 assert_eq!(bytes[3], 0x00);
858 assert_eq!(bytes[4], 0x11);
859 assert_eq!(bytes[5], 0x11);
860 }
861
862 #[test]
863 fn write_single_register() {
864 let res = Response::WriteSingleRegister(0x07, 0xABCD);
865 let bytes = &mut [0; 5];
866 res.encode(bytes).unwrap();
867 assert_eq!(bytes[0], 6);
868 assert_eq!(bytes[1], 0x00);
869 assert_eq!(bytes[2], 0x07);
870 assert_eq!(bytes[3], 0xAB);
871 assert_eq!(bytes[4], 0xCD);
872 }
873
874 #[test]
875 fn write_multiple_registers() {
876 let res = Response::WriteMultipleRegisters(0x06, 2);
877 let bytes = &mut [0; 5];
878 res.encode(bytes).unwrap();
879 assert_eq!(bytes[0], 0x10);
880 assert_eq!(bytes[1], 0x00);
881 assert_eq!(bytes[2], 0x06);
882 assert_eq!(bytes[3], 0x00);
883 assert_eq!(bytes[4], 0x02);
884 }
885
886 #[test]
887 fn read_write_multiple_registers() {
888 let buf: &mut [u8] = &mut [0; 2];
889 let res =
890 Response::ReadWriteMultipleRegisters(Data::from_words(&[0x1234], buf).unwrap());
891 let bytes = &mut [0; 4];
892 res.encode(bytes).unwrap();
893 assert_eq!(bytes[0], 0x17);
894 assert_eq!(bytes[1], 0x02);
895 assert_eq!(bytes[2], 0x12);
896 assert_eq!(bytes[3], 0x34);
897 }
898
899 #[test]
900 fn custom() {
901 let res = Response::Custom(FunctionCode::Custom(0x55), &[0xCC, 0x88, 0xAA, 0xFF]);
902 let bytes = &mut [0; 5];
903 res.encode(bytes).unwrap();
904 assert_eq!(bytes[0], 0x55);
905 assert_eq!(bytes[1], 0xCC);
906 assert_eq!(bytes[2], 0x88);
907 assert_eq!(bytes[3], 0xAA);
908 assert_eq!(bytes[4], 0xFF);
909 }
910 }
911
912 mod deserialize_responses {
913 use super::*;
914
915 #[test]
916 fn read_coils() {
917 let bytes: &[u8] = &[1, 1, 0b_0000_1001];
918 let rsp = Response::try_from(bytes).unwrap();
919 assert_eq!(
920 rsp,
921 Response::ReadCoils(Coils {
922 quantity: 8,
923 data: &[0b_0000_1001]
924 })
925 );
926 }
927
928 #[test]
929 fn read_no_coils() {
930 let bytes: &[u8] = &[1, 0];
931 let rsp = Response::try_from(bytes).unwrap();
932 assert_eq!(
933 rsp,
934 Response::ReadCoils(Coils {
935 quantity: 0,
936 data: &[]
937 })
938 );
939 }
940
941 #[test]
942 fn read_coils_with_invalid_byte_count() {
943 let bytes: &[u8] = &[1, 2, 0x6];
944 assert!(Response::try_from(bytes).is_err());
945 }
946
947 #[test]
948 fn read_discrete_inputs() {
949 let bytes: &[u8] = &[2, 1, 0b_0000_1001];
950 let rsp = Response::try_from(bytes).unwrap();
951 assert_eq!(
952 rsp,
953 Response::ReadDiscreteInputs(Coils {
954 quantity: 8,
955 data: &[0b_0000_1001]
956 })
957 );
958 }
959
960 #[test]
961 fn write_single_coil() {
962 let bytes: &[u8] = &[5, 0x00, 0x33];
963 let rsp = Response::try_from(bytes).unwrap();
964 assert_eq!(rsp, Response::WriteSingleCoil(0x33));
965
966 let broken_bytes: &[u8] = &[5, 0x00];
967 assert!(Response::try_from(broken_bytes).is_err());
968 }
969
970 #[test]
971 fn write_multiple_coils() {
972 let bytes: &[u8] = &[0x0F, 0x33, 0x11, 0x00, 0x05];
973 let rsp = Response::try_from(bytes).unwrap();
974 assert_eq!(rsp, Response::WriteMultipleCoils(0x3311, 5));
975 let broken_bytes: &[u8] = &[0x0F, 0x33, 0x11, 0x00];
976 assert!(Response::try_from(broken_bytes).is_err());
977 }
978
979 #[test]
980 fn read_input_registers() {
981 let bytes: &[u8] = &[4, 0x06, 0xAA, 0x00, 0xCC, 0xBB, 0xEE, 0xDD];
982 let rsp = Response::try_from(bytes).unwrap();
983 assert_eq!(
984 rsp,
985 Response::ReadInputRegisters(Data {
986 quantity: 3,
987 data: &[0xAA, 0x00, 0xCC, 0xBB, 0xEE, 0xDD]
988 })
989 );
990 }
991
992 #[test]
993 fn read_holding_registers() {
994 let bytes: &[u8] = &[3, 0x04, 0xAA, 0x00, 0x11, 0x11];
995 let rsp = Response::try_from(bytes).unwrap();
996 assert_eq!(
997 rsp,
998 Response::ReadHoldingRegisters(Data {
999 quantity: 2,
1000 data: &[0xAA, 0x00, 0x11, 0x11]
1001 })
1002 );
1003 }
1004
1005 #[test]
1006 fn write_single_register() {
1007 let bytes: &[u8] = &[6, 0x00, 0x07, 0xAB, 0xCD];
1008 let rsp = Response::try_from(bytes).unwrap();
1009 assert_eq!(rsp, Response::WriteSingleRegister(0x07, 0xABCD));
1010 let broken_bytes: &[u8] = &[6, 0x00, 0x07, 0xAB];
1011 assert!(Response::try_from(broken_bytes).is_err());
1012 }
1013
1014 #[test]
1015 fn write_multiple_registers() {
1016 let bytes: &[u8] = &[0x10, 0x00, 0x06, 0x00, 0x02];
1017 let rsp = Response::try_from(bytes).unwrap();
1018 assert_eq!(rsp, Response::WriteMultipleRegisters(0x06, 2));
1019 let broken_bytes: &[u8] = &[0x10, 0x00, 0x06, 0x00];
1020 assert!(Response::try_from(broken_bytes).is_err());
1021 }
1022
1023 #[test]
1024 fn read_write_multiple_registers() {
1025 let bytes: &[u8] = &[0x17, 0x02, 0x12, 0x34];
1026 let rsp = Response::try_from(bytes).unwrap();
1027 assert_eq!(
1028 rsp,
1029 Response::ReadWriteMultipleRegisters(Data {
1030 quantity: 1,
1031 data: &[0x12, 0x34]
1032 })
1033 );
1034 let broken_bytes: &[u8] = &[0x17, 0x02, 0x12];
1035 assert!(Response::try_from(broken_bytes).is_err());
1036 }
1037
1038 #[test]
1039 fn custom() {
1040 let bytes: &[u8] = &[0x55, 0xCC, 0x88, 0xAA, 0xFF];
1041 let rsp = Response::try_from(bytes).unwrap();
1042 assert_eq!(
1043 rsp,
1044 Response::Custom(FunctionCode::Custom(0x55), &[0xCC, 0x88, 0xAA, 0xFF])
1045 );
1046 let bytes: &[u8] = &[0x66];
1047 let rsp = Response::try_from(bytes).unwrap();
1048 assert_eq!(rsp, Response::Custom(FunctionCode::Custom(0x66), &[]));
1049 }
1050 }
1051}