1use std::{
5 convert::TryFrom,
6 io::{self, BufRead as _, Cursor, Error, ErrorKind},
7};
8
9use byteorder::{BigEndian, ReadBytesExt as _};
10
11use crate::{
12 bytes::{Buf as _, Bytes},
13 frame::{Coil, RequestPdu, ResponsePdu},
14 ExceptionCode, ExceptionResponse, FunctionCode, Request, Response,
15};
16
17#[cfg(feature = "rtu")]
18pub(crate) mod rtu;
19
20#[cfg(feature = "tcp")]
21pub(crate) mod tcp;
22
23const MAX_PDU_SIZE: usize = 253;
27
28#[cfg(any(test, feature = "rtu", feature = "tcp"))]
29#[allow(clippy::cast_possible_truncation)]
30fn u16_len(len: usize) -> u16 {
31 debug_assert!(len <= u16::MAX.into());
35 len as u16
36}
37
38#[cfg(any(test, feature = "rtu", feature = "tcp"))]
39#[allow(clippy::cast_possible_truncation)]
40fn u8_len(len: usize) -> u8 {
41 debug_assert!(len <= u8::MAX.into());
45 len as u8
46}
47
48#[cfg(any(test, feature = "rtu", feature = "tcp"))]
49fn encode_request_pdu(buf: &mut crate::bytes::BytesMut, request: &Request<'_>) {
50 use crate::{bytes::BufMut as _, frame::Request::*};
51 buf.put_u8(request.function_code().value());
52 match request {
53 ReadCoils(address, quantity)
54 | ReadDiscreteInputs(address, quantity)
55 | ReadInputRegisters(address, quantity)
56 | ReadHoldingRegisters(address, quantity) => {
57 buf.put_u16(*address);
58 buf.put_u16(*quantity);
59 }
60 WriteSingleCoil(address, state) => {
61 buf.put_u16(*address);
62 buf.put_u16(bool_to_coil(*state));
63 }
64 WriteMultipleCoils(address, coils) => {
65 buf.put_u16(*address);
66 buf.put_u16(u16_len(coils.len()));
67 buf.put_u8(u8_len(packed_coils_size(coils)));
68 encode_packed_coils(buf, coils);
69 }
70 WriteSingleRegister(address, word) => {
71 buf.put_u16(*address);
72 buf.put_u16(*word);
73 }
74 WriteMultipleRegisters(address, words) => {
75 buf.put_u16(*address);
76 let len = words.len();
77 buf.put_u16(u16_len(len));
78 buf.put_u8(u8_len(len * 2));
79 for w in words.as_ref() {
80 buf.put_u16(*w);
81 }
82 }
83 ReportServerId => {}
84 MaskWriteRegister(address, and_mask, or_mask) => {
85 buf.put_u16(*address);
86 buf.put_u16(*and_mask);
87 buf.put_u16(*or_mask);
88 }
89 ReadWriteMultipleRegisters(read_address, quantity, write_address, words) => {
90 buf.put_u16(*read_address);
91 buf.put_u16(*quantity);
92 buf.put_u16(*write_address);
93 let len = words.len();
94 buf.put_u16(u16_len(len));
95 buf.put_u8(u8_len(len * 2));
96 for w in words.as_ref() {
97 buf.put_u16(*w);
98 }
99 }
100 Custom(_, custom_data) => {
101 buf.put_slice(custom_data.as_ref());
102 }
103 }
104}
105
106#[cfg(any(test, feature = "server"))]
107fn encode_response_pdu(buf: &mut crate::bytes::BytesMut, response: &Response) {
108 use crate::{bytes::BufMut as _, frame::Response::*};
109 buf.put_u8(response.function_code().value());
110 match response {
111 ReadCoils(coils) | ReadDiscreteInputs(coils) => {
112 buf.put_u8(u8_len(packed_coils_size(coils)));
113 encode_packed_coils(buf, coils);
114 }
115 ReadInputRegisters(registers)
116 | ReadHoldingRegisters(registers)
117 | ReadWriteMultipleRegisters(registers) => {
118 buf.put_u8(u8_len(registers.len() * 2));
119 for r in registers {
120 buf.put_u16(*r);
121 }
122 }
123 WriteSingleCoil(address, state) => {
124 buf.put_u16(*address);
125 buf.put_u16(bool_to_coil(*state));
126 }
127 WriteMultipleCoils(address, quantity) | WriteMultipleRegisters(address, quantity) => {
128 buf.put_u16(*address);
129 buf.put_u16(*quantity);
130 }
131 ReportServerId(server_id, run_indication, additional_data) => {
132 buf.put_u8(2 + u8_len(additional_data.len()));
133 buf.put_u8(*server_id);
134 buf.put_u8(if *run_indication { 0xFF } else { 0x00 });
135 buf.put_slice(additional_data);
136 }
137 WriteSingleRegister(address, word) => {
138 buf.put_u16(*address);
139 buf.put_u16(*word);
140 }
141 MaskWriteRegister(address, and_mask, or_mask) => {
142 buf.put_u16(*address);
143 buf.put_u16(*and_mask);
144 buf.put_u16(*or_mask);
145 }
146 Custom(_, custom_data) => {
147 buf.put_slice(custom_data);
148 }
149 }
150}
151
152#[cfg(any(test, feature = "server"))]
153fn encode_exception_response_pdu(buf: &mut crate::bytes::BytesMut, response: ExceptionResponse) {
154 use crate::bytes::BufMut as _;
155 debug_assert!(response.function.value() < 0x80);
156 buf.put_u8(response.function.value() + 0x80);
157 buf.put_u8(response.exception.into());
158}
159
160#[cfg(feature = "server")]
161fn encode_response_result_pdu(
162 buf: &mut crate::bytes::BytesMut,
163 res: &Result<Response, ExceptionResponse>,
164) {
165 match res {
166 Ok(response) => encode_response_pdu(buf, response),
167 Err(response) => encode_exception_response_pdu(buf, *response),
168 }
169}
170
171fn read_u16_be(reader: &mut impl io::Read) -> io::Result<u16> {
172 reader.read_u16::<BigEndian>()
173}
174
175fn check_request_pdu_size(pdu_size: usize) -> io::Result<()> {
177 if pdu_size > MAX_PDU_SIZE {
178 return Err(io::Error::new(
179 ErrorKind::InvalidData,
180 "request PDU size exceeded",
181 ));
182 }
183 Ok(())
184}
185
186#[allow(clippy::too_many_lines)] fn decode_request_pdu_bytes(bytes: &Bytes) -> io::Result<Request<'static>> {
188 use crate::frame::Request::*;
189 let pdu_size = bytes.len();
190 let rdr = &mut Cursor::new(&bytes);
191 let fn_code = rdr.read_u8()?;
192 let req = match fn_code {
193 0x01 => ReadCoils(read_u16_be(rdr)?, read_u16_be(rdr)?),
194 0x02 => ReadDiscreteInputs(read_u16_be(rdr)?, read_u16_be(rdr)?),
195 0x05 => WriteSingleCoil(read_u16_be(rdr)?, coil_to_bool(read_u16_be(rdr)?)?),
196 0x0F => {
197 check_request_pdu_size(pdu_size)?;
198 let address = read_u16_be(rdr)?;
199 let quantity = read_u16_be(rdr)?;
200 let byte_count = usize::from(rdr.read_u8()?);
201 if bytes.len() < 6 + byte_count {
202 return Err(io::Error::new(ErrorKind::InvalidData, "too short"));
203 }
204 rdr.consume(byte_count);
205 let packed_coils = &bytes[6..6 + byte_count];
206 WriteMultipleCoils(address, decode_packed_coils(packed_coils, quantity).into())
207 }
208 0x04 => ReadInputRegisters(read_u16_be(rdr)?, read_u16_be(rdr)?),
209 0x03 => ReadHoldingRegisters(read_u16_be(rdr)?, read_u16_be(rdr)?),
210 0x06 => WriteSingleRegister(read_u16_be(rdr)?, read_u16_be(rdr)?),
211 0x10 => {
212 check_request_pdu_size(pdu_size)?;
213 let address = read_u16_be(rdr)?;
214 let quantity = read_u16_be(rdr)?;
215 let byte_count = rdr.read_u8()?;
216 if u16::from(byte_count) != quantity * 2 {
217 return Err(io::Error::new(ErrorKind::InvalidData, "invalid quantity"));
218 }
219 let mut data = Vec::with_capacity(quantity.into());
220 for _ in 0..quantity {
221 data.push(read_u16_be(rdr)?);
222 }
223 WriteMultipleRegisters(address, data.into())
224 }
225 0x11 => ReportServerId,
226 0x16 => {
227 let address = read_u16_be(rdr)?;
228 let and_mask = read_u16_be(rdr)?;
229 let or_mask = read_u16_be(rdr)?;
230 MaskWriteRegister(address, and_mask, or_mask)
231 }
232 0x17 => {
233 check_request_pdu_size(pdu_size)?;
234 let read_address = read_u16_be(rdr)?;
235 let read_quantity = read_u16_be(rdr)?;
236 let write_address = read_u16_be(rdr)?;
237 let write_quantity = read_u16_be(rdr)?;
238 let write_count = rdr.read_u8()?;
239 if u16::from(write_count) != write_quantity * 2 {
240 return Err(io::Error::new(
241 ErrorKind::InvalidData,
242 "invalid write quantity",
243 ));
244 }
245 let mut data = Vec::with_capacity(write_quantity.into());
246 for _ in 0..write_quantity {
247 data.push(read_u16_be(rdr)?);
248 }
249 ReadWriteMultipleRegisters(read_address, read_quantity, write_address, data.into())
250 }
251 fn_code if fn_code < 0x80 => {
252 return Ok(Custom(fn_code, bytes[1..].to_vec().into()));
254 }
255 fn_code => {
256 return Err(Error::new(
257 ErrorKind::InvalidData,
258 format!("invalid function code: 0x{fn_code:02X}"),
259 ));
260 }
261 };
262 if rdr.has_remaining() {
264 return Err(io::Error::new(
265 io::ErrorKind::InvalidData,
266 "undecoded request data",
267 ));
268 }
269 Ok(req)
270}
271
272impl TryFrom<Bytes> for Request<'static> {
273 type Error = Error;
274
275 fn try_from(pdu_bytes: Bytes) -> Result<Self, Self::Error> {
276 decode_request_pdu_bytes(&pdu_bytes)
277 }
278}
279
280impl TryFrom<Bytes> for RequestPdu<'static> {
281 type Error = Error;
282
283 fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
284 let pdu = Request::try_from(bytes)?.into();
285 Ok(pdu)
286 }
287}
288
289fn check_response_pdu_size(pdu_size: usize) -> io::Result<()> {
291 if pdu_size > MAX_PDU_SIZE {
292 return Err(io::Error::new(
293 ErrorKind::InvalidInput,
294 "response PDU size exceeded",
295 ));
296 }
297 Ok(())
298}
299
300#[allow(clippy::too_many_lines)] fn decode_response_pdu_bytes(bytes: Bytes) -> io::Result<Response> {
302 use crate::frame::Response::*;
303 let pdu_size = bytes.len();
304 let rdr = &mut Cursor::new(&bytes);
305 let fn_code = rdr.read_u8()?;
306 let response = match fn_code {
307 0x01 => {
308 check_response_pdu_size(pdu_size)?;
309 let byte_count = rdr.read_u8()?;
310 if bytes.len() < 2 + usize::from(byte_count) {
311 return Err(io::Error::new(ErrorKind::InvalidData, "too short"));
312 }
313 let packed_coils = &bytes[2..2 + usize::from(byte_count)];
314 rdr.consume(byte_count.into());
315 let quantity = u16::from(byte_count) * 8;
318 ReadCoils(decode_packed_coils(packed_coils, quantity))
319 }
320 0x02 => {
321 check_response_pdu_size(pdu_size)?;
322 let byte_count = rdr.read_u8()?;
323 if bytes.len() < 2 + usize::from(byte_count) {
324 return Err(io::Error::new(ErrorKind::InvalidData, "too short"));
325 }
326 let packed_coils = &bytes[2..2 + usize::from(byte_count)];
327 rdr.consume(byte_count.into());
328 let quantity = u16::from(byte_count) * 8;
331 ReadDiscreteInputs(decode_packed_coils(packed_coils, quantity))
332 }
333 0x05 => WriteSingleCoil(read_u16_be(rdr)?, coil_to_bool(read_u16_be(rdr)?)?),
334 0x0F => WriteMultipleCoils(read_u16_be(rdr)?, read_u16_be(rdr)?),
335 0x04 => {
336 check_response_pdu_size(pdu_size)?;
337 let byte_count = rdr.read_u8()?;
338 if byte_count % 2 != 0 {
339 return Err(io::Error::new(
340 io::ErrorKind::InvalidData,
341 "invalid quantity",
342 ));
343 }
344 let quantity = byte_count / 2;
345 let mut data = Vec::with_capacity(quantity.into());
346 for _ in 0..quantity {
347 data.push(read_u16_be(rdr)?);
348 }
349 ReadInputRegisters(data)
350 }
351 0x03 => {
352 check_response_pdu_size(pdu_size)?;
353 let byte_count = rdr.read_u8()?;
354 if byte_count % 2 != 0 {
355 return Err(io::Error::new(
356 io::ErrorKind::InvalidData,
357 "invalid quantity",
358 ));
359 }
360 let quantity = byte_count / 2;
361 let mut data = Vec::with_capacity(quantity.into());
362 for _ in 0..quantity {
363 data.push(read_u16_be(rdr)?);
364 }
365 ReadHoldingRegisters(data)
366 }
367 0x06 => WriteSingleRegister(read_u16_be(rdr)?, read_u16_be(rdr)?),
368 0x10 => WriteMultipleRegisters(read_u16_be(rdr)?, read_u16_be(rdr)?),
369 0x11 => {
370 check_response_pdu_size(pdu_size)?;
371 let byte_count = rdr.read_u8()?;
372 if byte_count < 2 {
373 return Err(io::Error::new(io::ErrorKind::InvalidData, "too short"));
374 }
375 let data_len = (byte_count - 2).into();
376 let server_id = rdr.read_u8()?;
377 let run_indication_status = match rdr.read_u8()? {
378 0x00 => false,
379 0xFF => true,
380 status => {
381 return Err(Error::new(
382 ErrorKind::InvalidData,
383 format!("invalid run indication status: 0x{status:02X}"),
384 ));
385 }
386 };
387 let mut data = Vec::with_capacity(data_len);
388 for _ in 0..data_len {
389 data.push(rdr.read_u8()?);
390 }
391 ReportServerId(server_id, run_indication_status, data)
392 }
393 0x16 => {
394 let address = read_u16_be(rdr)?;
395 let and_mask = read_u16_be(rdr)?;
396 let or_mask = read_u16_be(rdr)?;
397 MaskWriteRegister(address, and_mask, or_mask)
398 }
399 0x17 => {
400 check_response_pdu_size(pdu_size)?;
401 let byte_count = rdr.read_u8()?;
402 if byte_count % 2 != 0 {
403 return Err(io::Error::new(
404 io::ErrorKind::InvalidData,
405 "invalid quantity",
406 ));
407 }
408 let quantity = byte_count / 2;
409 let mut data = Vec::with_capacity(quantity.into());
410 for _ in 0..quantity {
411 data.push(read_u16_be(rdr)?);
412 }
413 ReadWriteMultipleRegisters(data)
414 }
415 _ => {
416 let mut bytes = bytes;
418 return Ok(Custom(fn_code, bytes.split_off(1)));
419 }
420 };
421 if rdr.has_remaining() {
423 return Err(io::Error::new(
424 io::ErrorKind::InvalidData,
425 "undecoded response data",
426 ));
427 }
428 Ok(response)
429}
430
431impl TryFrom<Bytes> for Response {
432 type Error = Error;
433
434 fn try_from(pdu_bytes: Bytes) -> Result<Self, Self::Error> {
435 decode_response_pdu_bytes(pdu_bytes)
436 }
437}
438
439impl TryFrom<Bytes> for ExceptionResponse {
440 type Error = Error;
441
442 fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
443 let mut rdr = Cursor::new(&bytes);
444 let fn_err_code = rdr.read_u8()?;
445 if fn_err_code < 0x80 {
446 return Err(Error::new(
447 ErrorKind::InvalidData,
448 "Invalid exception function code",
449 ));
450 }
451 let function = fn_err_code - 0x80;
452 let exception = ExceptionCode::new(rdr.read_u8()?);
453 Ok(ExceptionResponse {
454 function: FunctionCode::new(function),
455 exception,
456 })
457 }
458}
459
460impl TryFrom<Bytes> for ResponsePdu {
461 type Error = Error;
462
463 fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
464 let fn_code = Cursor::new(&bytes).read_u8()?;
465 let pdu = if fn_code < 0x80 {
466 Response::try_from(bytes)?.into()
467 } else {
468 ExceptionResponse::try_from(bytes)?.into()
469 };
470 Ok(pdu)
471 }
472}
473
474#[cfg(any(test, feature = "rtu", feature = "tcp"))]
475fn bool_to_coil(state: bool) -> u16 {
476 if state {
477 0xFF00
478 } else {
479 0x0000
480 }
481}
482
483fn coil_to_bool(coil: u16) -> io::Result<bool> {
484 match coil {
485 0xFF00 => Ok(true),
486 0x0000 => Ok(false),
487 _ => Err(Error::new(ErrorKind::InvalidData, "Invalid coil value: {}")),
488 }
489}
490
491#[cfg(any(test, feature = "rtu", feature = "tcp"))]
492fn packed_coils_size(coils: &[Coil]) -> usize {
493 coils.len().div_ceil(8)
494}
495
496#[cfg(any(test, feature = "rtu", feature = "tcp"))]
497fn encode_packed_coils(buf: &mut crate::bytes::BytesMut, coils: &[Coil]) -> usize {
498 let packed_coils_size = packed_coils_size(coils);
499 let offset = buf.len();
500 buf.resize(offset + packed_coils_size, 0);
501 let buf = &mut buf[offset..];
502 for (i, b) in coils.iter().enumerate() {
503 let v = u8::from(*b); buf[i / 8] |= v << (i % 8);
505 }
506 packed_coils_size
507}
508
509fn decode_packed_coils(bytes: &[u8], count: u16) -> Vec<Coil> {
510 let mut res = Vec::with_capacity(count.into());
511 for i in 0usize..count.into() {
512 res.push((bytes[i / 8] >> (i % 8)) & 0b1 > 0);
513 }
514 res
515}
516
517#[cfg(any(feature = "rtu", feature = "tcp"))]
518fn request_pdu_size(request: &Request<'_>) -> io::Result<usize> {
519 use crate::frame::Request::*;
520 let size = match request {
521 ReadCoils(_, _)
522 | ReadDiscreteInputs(_, _)
523 | ReadInputRegisters(_, _)
524 | ReadHoldingRegisters(_, _)
525 | WriteSingleRegister(_, _)
526 | WriteSingleCoil(_, _) => 5,
527 WriteMultipleCoils(_, coils) => 6 + packed_coils_size(coils),
528 WriteMultipleRegisters(_, data) => 6 + data.len() * 2,
529 ReportServerId => 1,
530 MaskWriteRegister(_, _, _) => 7,
531 ReadWriteMultipleRegisters(_, _, _, data) => 10 + data.len() * 2,
532 Custom(_, data) => 1 + data.len(),
533 };
534 if size > MAX_PDU_SIZE {
535 return Err(io::Error::new(
536 ErrorKind::InvalidInput,
537 "request PDU size exceeded",
538 ));
539 }
540 Ok(size)
541}
542
543#[cfg(feature = "server")]
544fn response_pdu_size(response: &Response) -> io::Result<usize> {
545 use crate::frame::Response::*;
546 let size = match response {
547 ReadCoils(coils) | ReadDiscreteInputs(coils) => 2 + packed_coils_size(coils),
548 WriteSingleCoil(_, _)
549 | WriteMultipleCoils(_, _)
550 | WriteMultipleRegisters(_, _)
551 | WriteSingleRegister(_, _) => 5,
552 ReadInputRegisters(data)
553 | ReadHoldingRegisters(data)
554 | ReadWriteMultipleRegisters(data) => 2 + data.len() * 2,
555 ReportServerId(_, _, data) => 3 + data.len(),
556 MaskWriteRegister(_, _, _) => 7,
557 Custom(_, data) => 1 + data.len(),
558 };
559 if size > MAX_PDU_SIZE {
560 return Err(io::Error::new(
561 ErrorKind::InvalidInput,
562 "response PDU size exceeded",
563 ));
564 }
565 Ok(size)
566}
567
568#[cfg(feature = "server")]
569fn response_result_pdu_size(res: &Result<Response, ExceptionResponse>) -> io::Result<usize> {
570 match res {
571 Ok(response) => response_pdu_size(response),
572 Err(_) => Ok(2),
573 }
574}
575
576#[cfg(test)]
577mod tests {
578
579 use std::borrow::Cow;
580
581 use crate::bytes::BytesMut;
582
583 use super::*;
584
585 fn encode_request_pdu_to_bytes(request: &Request<'_>) -> Bytes {
586 let mut buf = BytesMut::new();
587 encode_request_pdu(&mut buf, request);
588 buf.freeze()
589 }
590
591 fn encode_response_pdu_to_bytes(response: &Response) -> Bytes {
592 let mut buf = BytesMut::new();
593 encode_response_pdu(&mut buf, response);
594 buf.freeze()
595 }
596
597 fn encode_exception_response_pdu_to_bytes(response: ExceptionResponse) -> Bytes {
598 let mut buf = BytesMut::new();
599 encode_exception_response_pdu(&mut buf, response);
600 buf.freeze()
601 }
602
603 fn encode_packed_coils_to_bytes(coils: &[Coil]) -> Bytes {
604 let mut buf = BytesMut::new();
605 encode_packed_coils(&mut buf, coils);
606 buf.freeze()
607 }
608
609 #[test]
610 fn convert_bool_to_coil() {
611 assert_eq!(bool_to_coil(true), 0xFF00);
612 assert_eq!(bool_to_coil(false), 0x0000);
613 }
614
615 #[test]
616 fn convert_coil_to_bool() {
617 assert!(coil_to_bool(0xFF00).unwrap());
618 assert!(!coil_to_bool(0x0000).unwrap());
619 }
620
621 #[test]
622 fn convert_booleans_to_bytes() {
623 assert_eq!(&encode_packed_coils_to_bytes(&[])[..], &[]);
624 assert_eq!(&encode_packed_coils_to_bytes(&[true])[..], &[0b1]);
625 assert_eq!(&encode_packed_coils_to_bytes(&[false])[..], &[0b0]);
626 assert_eq!(&encode_packed_coils_to_bytes(&[true, false])[..], &[0b_01]);
627 assert_eq!(&encode_packed_coils_to_bytes(&[false, true])[..], &[0b_10]);
628 assert_eq!(&encode_packed_coils_to_bytes(&[true, true])[..], &[0b_11]);
629 assert_eq!(
630 &encode_packed_coils_to_bytes(&[true; 8])[..],
631 &[0b_1111_1111]
632 );
633 assert_eq!(&encode_packed_coils_to_bytes(&[true; 9])[..], &[255, 1]);
634 assert_eq!(&encode_packed_coils_to_bytes(&[false; 8])[..], &[0]);
635 assert_eq!(&encode_packed_coils_to_bytes(&[false; 9])[..], &[0, 0]);
636 }
637
638 #[test]
639 fn test_unpack_bits() {
640 assert_eq!(decode_packed_coils(&[], 0), &[]);
641 assert_eq!(decode_packed_coils(&[0, 0], 0), &[]);
642 assert_eq!(decode_packed_coils(&[0b1], 1), &[true]);
643 assert_eq!(decode_packed_coils(&[0b01], 2), &[true, false]);
644 assert_eq!(decode_packed_coils(&[0b10], 2), &[false, true]);
645 assert_eq!(decode_packed_coils(&[0b101], 3), &[true, false, true]);
646 assert_eq!(decode_packed_coils(&[0xff, 0b11], 10), &[true; 10]);
647 }
648
649 #[test]
650 fn exception_response_into_bytes() {
651 let bytes = encode_exception_response_pdu_to_bytes(ExceptionResponse {
652 function: FunctionCode::ReadHoldingRegisters,
653 exception: ExceptionCode::IllegalDataAddress,
654 });
655 assert_eq!(bytes[0], 0x83);
656 assert_eq!(bytes[1], 0x02);
657 }
658
659 #[test]
660 fn exception_response_from_bytes() {
661 assert!(ExceptionResponse::try_from(Bytes::from(vec![0x79, 0x02])).is_err());
662
663 let bytes = Bytes::from(vec![0x83, 0x02]);
664 let response = ExceptionResponse::try_from(bytes).unwrap();
665 assert_eq!(
666 response,
667 ExceptionResponse {
668 function: FunctionCode::ReadHoldingRegisters,
669 exception: ExceptionCode::IllegalDataAddress,
670 }
671 );
672 }
673
674 #[test]
675 fn pdu_into_bytes() {
676 let req_pdu = encode_request_pdu_to_bytes(&Request::ReadCoils(0x01, 5));
677 let response_pdu = encode_response_pdu_to_bytes(&Response::ReadCoils(vec![]));
678 let ex_pdu = encode_exception_response_pdu_to_bytes(ExceptionResponse {
679 function: FunctionCode::ReadHoldingRegisters,
680 exception: ExceptionCode::ServerDeviceFailure,
681 });
682
683 assert_eq!(req_pdu[0], 0x01);
684 assert_eq!(req_pdu[1], 0x00);
685 assert_eq!(req_pdu[2], 0x01);
686 assert_eq!(req_pdu[3], 0x00);
687 assert_eq!(req_pdu[4], 0x05);
688
689 assert_eq!(response_pdu[0], 0x01);
690 assert_eq!(response_pdu[1], 0x00);
691
692 assert_eq!(ex_pdu[0], 0x83);
693 assert_eq!(ex_pdu[1], 0x04);
694
695 let req_pdu = encode_request_pdu_to_bytes(&Request::ReadHoldingRegisters(0x082B, 2));
696 assert_eq!(req_pdu.len(), 5);
697 assert_eq!(req_pdu[0], 0x03);
698 assert_eq!(req_pdu[1], 0x08);
699 assert_eq!(req_pdu[2], 0x2B);
700 assert_eq!(req_pdu[3], 0x00);
701 assert_eq!(req_pdu[4], 0x02);
702 }
703
704 #[test]
705 fn pdu_with_a_lot_of_data_into_bytes() {
706 let _req_pdu = encode_request_pdu_to_bytes(&Request::WriteMultipleRegisters(
707 0x01,
708 Cow::Borrowed(&[0; 80]),
709 ));
710 let _response_pdu =
711 encode_response_pdu_to_bytes(&Response::ReadInputRegisters(vec![0; 80]));
712 }
713
714 mod serialize_requests {
715
716 use super::*;
717
718 #[test]
719 fn read_coils() {
720 let bytes = encode_request_pdu_to_bytes(&Request::ReadCoils(0x12, 4));
721 assert_eq!(bytes[0], 1);
722 assert_eq!(bytes[1], 0x00);
723 assert_eq!(bytes[2], 0x12);
724 assert_eq!(bytes[3], 0x00);
725 assert_eq!(bytes[4], 0x04);
726 }
727
728 #[test]
729 fn read_discrete_inputs() {
730 let bytes = encode_request_pdu_to_bytes(&Request::ReadDiscreteInputs(0x03, 19));
731 assert_eq!(bytes[0], 2);
732 assert_eq!(bytes[1], 0x00);
733 assert_eq!(bytes[2], 0x03);
734 assert_eq!(bytes[3], 0x00);
735 assert_eq!(bytes[4], 19);
736 }
737
738 #[test]
739 fn write_single_coil() {
740 let bytes = encode_request_pdu_to_bytes(&Request::WriteSingleCoil(0x1234, true));
741 assert_eq!(bytes[0], 5);
742 assert_eq!(bytes[1], 0x12);
743 assert_eq!(bytes[2], 0x34);
744 assert_eq!(bytes[3], 0xFF);
745 assert_eq!(bytes[4], 0x00);
746 }
747
748 #[test]
749 fn write_multiple_coils() {
750 let states = [true, false, true, true];
751 let bytes = encode_request_pdu_to_bytes(&Request::WriteMultipleCoils(
752 0x3311,
753 Cow::Borrowed(&states),
754 ));
755 assert_eq!(bytes[0], 0x0F);
756 assert_eq!(bytes[1], 0x33);
757 assert_eq!(bytes[2], 0x11);
758 assert_eq!(bytes[3], 0x00);
759 assert_eq!(bytes[4], 0x04);
760 assert_eq!(bytes[5], 0x01);
761 assert_eq!(bytes[6], 0b_0000_1101);
762 }
763
764 #[test]
765 fn read_input_registers() {
766 let bytes = encode_request_pdu_to_bytes(&Request::ReadInputRegisters(0x09, 77));
767 assert_eq!(bytes[0], 4);
768 assert_eq!(bytes[1], 0x00);
769 assert_eq!(bytes[2], 0x09);
770 assert_eq!(bytes[3], 0x00);
771 assert_eq!(bytes[4], 0x4D);
772 }
773
774 #[test]
775 fn read_holding_registers() {
776 let bytes = encode_request_pdu_to_bytes(&Request::ReadHoldingRegisters(0x09, 77));
777 assert_eq!(bytes[0], 3);
778 assert_eq!(bytes[1], 0x00);
779 assert_eq!(bytes[2], 0x09);
780 assert_eq!(bytes[3], 0x00);
781 assert_eq!(bytes[4], 0x4D);
782 }
783
784 #[test]
785 fn write_single_register() {
786 let bytes = encode_request_pdu_to_bytes(&Request::WriteSingleRegister(0x07, 0xABCD));
787 assert_eq!(bytes[0], 6);
788 assert_eq!(bytes[1], 0x00);
789 assert_eq!(bytes[2], 0x07);
790 assert_eq!(bytes[3], 0xAB);
791 assert_eq!(bytes[4], 0xCD);
792 }
793
794 #[test]
795 fn write_multiple_registers() {
796 let bytes = encode_request_pdu_to_bytes(&Request::WriteMultipleRegisters(
797 0x06,
798 Cow::Borrowed(&[0xABCD, 0xEF12]),
799 ));
800
801 assert_eq!(bytes[0], 0x10);
803
804 assert_eq!(bytes[1], 0x00);
806 assert_eq!(bytes[2], 0x06);
807
808 assert_eq!(bytes[3], 0x00);
810 assert_eq!(bytes[4], 0x02);
811
812 assert_eq!(bytes[5], 0x04);
814
815 assert_eq!(bytes[6], 0xAB);
817 assert_eq!(bytes[7], 0xCD);
818 assert_eq!(bytes[8], 0xEF);
819 assert_eq!(bytes[9], 0x12);
820 }
821
822 #[test]
823 fn report_server_id() {
824 let bytes = encode_request_pdu_to_bytes(&Request::ReportServerId);
825 assert_eq!(bytes[0], 0x11);
826 }
827
828 #[test]
829 fn masked_write_register() {
830 let bytes =
831 encode_request_pdu_to_bytes(&Request::MaskWriteRegister(0xABCD, 0xEF12, 0x2345));
832
833 assert_eq!(bytes[0], 0x16);
835
836 assert_eq!(bytes[1], 0xAB);
838 assert_eq!(bytes[2], 0xCD);
839
840 assert_eq!(bytes[3], 0xEF);
842 assert_eq!(bytes[4], 0x12);
843
844 assert_eq!(bytes[5], 0x23);
846 assert_eq!(bytes[6], 0x45);
847 }
848
849 #[test]
850 fn read_write_multiple_registers() {
851 let data = [0xABCD, 0xEF12];
852 let bytes = encode_request_pdu_to_bytes(&Request::ReadWriteMultipleRegisters(
853 0x05,
854 51,
855 0x03,
856 Cow::Borrowed(&data),
857 ));
858
859 assert_eq!(bytes[0], 0x17);
861
862 assert_eq!(bytes[1], 0x00);
864 assert_eq!(bytes[2], 0x05);
865
866 assert_eq!(bytes[3], 0x00);
868 assert_eq!(bytes[4], 0x33);
869
870 assert_eq!(bytes[5], 0x00);
872 assert_eq!(bytes[6], 0x03);
873
874 assert_eq!(bytes[7], 0x00);
876 assert_eq!(bytes[8], 0x02);
877
878 assert_eq!(bytes[9], 0x04);
880
881 assert_eq!(bytes[10], 0xAB);
883 assert_eq!(bytes[11], 0xCD);
884 assert_eq!(bytes[12], 0xEF);
885 assert_eq!(bytes[13], 0x12);
886 }
887
888 #[test]
889 fn custom() {
890 let bytes = encode_request_pdu_to_bytes(&Request::Custom(
891 0x55,
892 Cow::Borrowed(&[0xCC, 0x88, 0xAA, 0xFF]),
893 ));
894 assert_eq!(bytes[0], 0x55);
895 assert_eq!(bytes[1], 0xCC);
896 assert_eq!(bytes[2], 0x88);
897 assert_eq!(bytes[3], 0xAA);
898 assert_eq!(bytes[4], 0xFF);
899 }
900 }
901
902 mod deserialize_requests {
903
904 use super::*;
905
906 #[test]
907 fn empty_request() {
908 assert!(Request::try_from(Bytes::from(vec![])).is_err());
909 }
910
911 #[test]
912 fn read_coils() {
913 assert!(Request::try_from(Bytes::from(vec![0x01])).is_err());
914 assert!(Request::try_from(Bytes::from(vec![0x01, 0x0, 0x0, 0x22])).is_err());
915
916 let bytes = Bytes::from(vec![0x01, 0x00, 0x12, 0x0, 0x4]);
917 let req = Request::try_from(bytes).unwrap();
918 assert_eq!(req, Request::ReadCoils(0x12, 4));
919 }
920
921 #[test]
922 fn read_discrete_inputs() {
923 let bytes = Bytes::from(vec![2, 0x00, 0x03, 0x00, 19]);
924 let req = Request::try_from(bytes).unwrap();
925 assert_eq!(req, Request::ReadDiscreteInputs(0x03, 19));
926 }
927
928 #[test]
929 fn write_single_coil() {
930 let bytes = Bytes::from(vec![5, 0x12, 0x34, 0xFF, 0x00]);
931 let req = Request::try_from(bytes).unwrap();
932 assert_eq!(req, Request::WriteSingleCoil(0x1234, true));
933 }
934
935 #[test]
936 fn write_multiple_coils() {
937 assert!(Request::try_from(Bytes::from(vec![
938 0x0F,
939 0x33,
940 0x11,
941 0x00,
942 0x04,
943 0x02,
944 0b_0000_1101,
945 ]))
946 .is_err());
947
948 let bytes = Bytes::from(vec![0x0F, 0x33, 0x11, 0x00, 0x04, 0x01, 0b_0000_1101]);
949 let req = Request::try_from(bytes).unwrap();
950 assert_eq!(
951 req,
952 Request::WriteMultipleCoils(0x3311, Cow::Borrowed(&[true, false, true, true]))
953 );
954 }
955
956 #[test]
957 fn read_input_registers() {
958 let bytes = Bytes::from(vec![4, 0x00, 0x09, 0x00, 0x4D]);
959 let req = Request::try_from(bytes).unwrap();
960 assert_eq!(req, Request::ReadInputRegisters(0x09, 77));
961 }
962
963 #[test]
964 fn read_holding_registers() {
965 let bytes = Bytes::from(vec![3, 0x00, 0x09, 0x00, 0x4D]);
966 let req = Request::try_from(bytes).unwrap();
967 assert_eq!(req, Request::ReadHoldingRegisters(0x09, 77));
968 }
969
970 #[test]
971 fn write_single_register() {
972 let bytes = Bytes::from(vec![6, 0x00, 0x07, 0xAB, 0xCD]);
973 let req = Request::try_from(bytes).unwrap();
974 assert_eq!(req, Request::WriteSingleRegister(0x07, 0xABCD));
975 }
976
977 #[test]
978 fn write_multiple_registers() {
979 assert!(Request::try_from(Bytes::from(vec![
980 0x10, 0x00, 0x06, 0x00, 0x02, 0x05, 0xAB, 0xCD, 0xEF, 0x12,
981 ]))
982 .is_err());
983
984 let bytes = Bytes::from(vec![
985 0x10, 0x00, 0x06, 0x00, 0x02, 0x04, 0xAB, 0xCD, 0xEF, 0x12,
986 ]);
987 let req = Request::try_from(bytes).unwrap();
988 assert_eq!(
989 req,
990 Request::WriteMultipleRegisters(0x06, Cow::Borrowed(&[0xABCD, 0xEF12]))
991 );
992 }
993
994 #[test]
995 fn report_server_id() {
996 let bytes = Bytes::from(vec![0x11]);
997 let req = Request::try_from(bytes).unwrap();
998 assert_eq!(req, Request::ReportServerId);
999 }
1000
1001 #[test]
1002 fn masked_write_register() {
1003 let bytes = Bytes::from(vec![0x16, 0xAB, 0xCD, 0xEF, 0x12, 0x23, 0x45]);
1004 let req = Request::try_from(bytes).unwrap();
1005 assert_eq!(req, Request::MaskWriteRegister(0xABCD, 0xEF12, 0x2345));
1006 }
1007
1008 #[test]
1009 fn read_write_multiple_registers() {
1010 assert!(Request::try_from(Bytes::from(vec![
1011 0x17, 0x00, 0x05, 0x00, 0x33, 0x00, 0x03, 0x00, 0x02, 0x05, 0xAB, 0xCD, 0xEF, 0x12,
1012 ]))
1013 .is_err());
1014 let bytes = Bytes::from(vec![
1015 0x17, 0x00, 0x05, 0x00, 0x33, 0x00, 0x03, 0x00, 0x02, 0x04, 0xAB, 0xCD, 0xEF, 0x12,
1016 ]);
1017 let req = Request::try_from(bytes).unwrap();
1018 let data = [0xABCD, 0xEF12];
1019 assert_eq!(
1020 req,
1021 Request::ReadWriteMultipleRegisters(0x05, 51, 0x03, Cow::Borrowed(&data))
1022 );
1023 }
1024
1025 #[test]
1026 fn custom() {
1027 let bytes = Bytes::from(vec![0x55, 0xCC, 0x88, 0xAA, 0xFF]);
1028 let req = Request::try_from(bytes).unwrap();
1029 assert_eq!(
1030 req,
1031 Request::Custom(0x55, Cow::Borrowed(&[0xCC, 0x88, 0xAA, 0xFF]))
1032 );
1033 }
1034 }
1035
1036 mod serialize_responses {
1037
1038 use super::*;
1039
1040 #[test]
1041 fn read_coils() {
1042 let bytes = encode_response_pdu_to_bytes(&Response::ReadCoils(vec![
1043 true, false, false, true, false,
1044 ]));
1045 assert_eq!(bytes[0], 1);
1046 assert_eq!(bytes[1], 1);
1047 assert_eq!(bytes[2], 0b_0000_1001);
1048 }
1049
1050 #[test]
1051 fn read_discrete_inputs() {
1052 let bytes = encode_response_pdu_to_bytes(&Response::ReadDiscreteInputs(vec![
1053 true, false, true, true,
1054 ]));
1055 assert_eq!(bytes[0], 2);
1056 assert_eq!(bytes[1], 1);
1057 assert_eq!(bytes[2], 0b_0000_1101);
1058 }
1059
1060 #[test]
1061 fn write_single_coil() {
1062 let bytes = encode_response_pdu_to_bytes(&Response::WriteSingleCoil(0x33, true));
1063 assert_eq!(bytes[0], 5);
1064 assert_eq!(bytes[1], 0x00);
1065 assert_eq!(bytes[2], 0x33);
1066 assert_eq!(bytes[3], 0xFF);
1067 assert_eq!(bytes[4], 0x00);
1068 }
1069
1070 #[test]
1071 fn write_multiple_coils() {
1072 let bytes = encode_response_pdu_to_bytes(&Response::WriteMultipleCoils(0x3311, 5));
1073 assert_eq!(bytes[0], 0x0F);
1074 assert_eq!(bytes[1], 0x33);
1075 assert_eq!(bytes[2], 0x11);
1076 assert_eq!(bytes[3], 0x00);
1077 assert_eq!(bytes[4], 0x05);
1078 }
1079
1080 #[test]
1081 fn read_input_registers() {
1082 let bytes = encode_response_pdu_to_bytes(&Response::ReadInputRegisters(vec![
1083 0xAA00, 0xCCBB, 0xEEDD,
1084 ]));
1085 assert_eq!(bytes[0], 4);
1086 assert_eq!(bytes[1], 0x06);
1087 assert_eq!(bytes[2], 0xAA);
1088 assert_eq!(bytes[3], 0x00);
1089 assert_eq!(bytes[4], 0xCC);
1090 assert_eq!(bytes[5], 0xBB);
1091 assert_eq!(bytes[6], 0xEE);
1092 assert_eq!(bytes[7], 0xDD);
1093 }
1094
1095 #[test]
1096 fn read_holding_registers() {
1097 let bytes =
1098 encode_response_pdu_to_bytes(&Response::ReadHoldingRegisters(vec![0xAA00, 0x1111]));
1099 assert_eq!(bytes[0], 3);
1100 assert_eq!(bytes[1], 0x04);
1101 assert_eq!(bytes[2], 0xAA);
1102 assert_eq!(bytes[3], 0x00);
1103 assert_eq!(bytes[4], 0x11);
1104 assert_eq!(bytes[5], 0x11);
1105 }
1106
1107 #[test]
1108 fn write_single_register() {
1109 let bytes = encode_response_pdu_to_bytes(&Response::WriteSingleRegister(0x07, 0xABCD));
1110 assert_eq!(bytes[0], 6);
1111 assert_eq!(bytes[1], 0x00);
1112 assert_eq!(bytes[2], 0x07);
1113 assert_eq!(bytes[3], 0xAB);
1114 assert_eq!(bytes[4], 0xCD);
1115 }
1116
1117 #[test]
1118 fn write_multiple_registers() {
1119 let bytes = encode_response_pdu_to_bytes(&Response::WriteMultipleRegisters(0x06, 2));
1120 assert_eq!(bytes[0], 0x10);
1121 assert_eq!(bytes[1], 0x00);
1122 assert_eq!(bytes[2], 0x06);
1123 assert_eq!(bytes[3], 0x00);
1124 assert_eq!(bytes[4], 0x02);
1125 }
1126
1127 #[test]
1128 fn report_server_id() {
1129 let bytes = encode_response_pdu_to_bytes(&Response::ReportServerId(
1130 0x42,
1131 true,
1132 vec![0x10, 0x20],
1133 ));
1134 assert_eq!(bytes[0], 0x11);
1135 assert_eq!(bytes[1], 0x04);
1136 assert_eq!(bytes[2], 0x42);
1137 assert_eq!(bytes[3], 0xFF);
1138 assert_eq!(bytes[4], 0x10);
1139 assert_eq!(bytes[5], 0x20);
1140 }
1141
1142 #[test]
1143 fn masked_write_register() {
1144 let bytes =
1145 encode_response_pdu_to_bytes(&Response::MaskWriteRegister(0x06, 0x8001, 0x4002));
1146 assert_eq!(bytes[0], 0x16);
1147 assert_eq!(bytes[1], 0x00);
1148 assert_eq!(bytes[2], 0x06);
1149 assert_eq!(bytes[3], 0x80);
1150 assert_eq!(bytes[4], 0x01);
1151 assert_eq!(bytes[5], 0x40);
1152 assert_eq!(bytes[6], 0x02);
1153 }
1154
1155 #[test]
1156 fn read_write_multiple_registers() {
1157 let bytes =
1158 encode_response_pdu_to_bytes(&Response::ReadWriteMultipleRegisters(vec![0x1234]));
1159 assert_eq!(bytes[0], 0x17);
1160 assert_eq!(bytes[1], 0x02);
1161 assert_eq!(bytes[2], 0x12);
1162 assert_eq!(bytes[3], 0x34);
1163 }
1164
1165 #[test]
1166 fn custom() {
1167 let bytes = encode_response_pdu_to_bytes(&Response::Custom(
1168 0x55,
1169 Bytes::from_static(&[0xCC, 0x88, 0xAA, 0xFF]),
1170 ));
1171 assert_eq!(bytes[0], 0x55);
1172 assert_eq!(bytes[1], 0xCC);
1173 assert_eq!(bytes[2], 0x88);
1174 assert_eq!(bytes[3], 0xAA);
1175 assert_eq!(bytes[4], 0xFF);
1176 }
1177 }
1178
1179 mod deserialize_responses {
1180
1181 use super::*;
1182
1183 #[test]
1184 fn read_coils() {
1185 let bytes = Bytes::from(vec![1, 1, 0b_0000_1001]);
1186 let response = Response::try_from(bytes).unwrap();
1187 assert_eq!(
1188 response,
1189 Response::ReadCoils(vec![true, false, false, true, false, false, false, false])
1190 );
1191 }
1192
1193 #[test]
1194 fn read_coils_max_quantity() {
1195 let quantity = 2000;
1196 let byte_count = quantity / 8;
1197 let mut raw: Vec<u8> = vec![1, u8_len(byte_count)];
1198 let mut values: Vec<u8> = (0..byte_count).map(|_| 0b_1111_1111).collect();
1199 raw.append(&mut values);
1200 let bytes = Bytes::from(raw);
1201 let response = Response::try_from(bytes).unwrap();
1202 assert_eq!(response, Response::ReadCoils(vec![true; quantity]));
1203 }
1204
1205 #[test]
1206 fn read_discrete_inputs() {
1207 let bytes = Bytes::from(vec![2, 1, 0b_0000_1001]);
1208 let response = Response::try_from(bytes).unwrap();
1209 assert_eq!(
1210 response,
1211 Response::ReadDiscreteInputs(vec![
1212 true, false, false, true, false, false, false, false,
1213 ],)
1214 );
1215 }
1216
1217 #[test]
1218 fn read_discrete_inputs_max_quantity() {
1219 let quantity = 2000;
1220 let byte_count = quantity / 8;
1221 let mut raw: Vec<u8> = vec![2, u8_len(byte_count)];
1222 let mut values: Vec<u8> = (0..byte_count).map(|_| 0b_1111_1111).collect();
1223 raw.append(&mut values);
1224 let bytes = Bytes::from(raw);
1225 let response = Response::try_from(bytes).unwrap();
1226 assert_eq!(response, Response::ReadDiscreteInputs(vec![true; quantity]));
1227 }
1228
1229 #[test]
1230 fn write_single_coil() {
1231 let bytes = Bytes::from(vec![5, 0x00, 0x33, 0xFF, 0x00]);
1232 let response = Response::try_from(bytes).unwrap();
1233 assert_eq!(response, Response::WriteSingleCoil(0x33, true));
1234 }
1235
1236 #[test]
1237 fn write_multiple_coils() {
1238 let bytes = Bytes::from(vec![0x0F, 0x33, 0x11, 0x00, 0x05]);
1239 let response = Response::try_from(bytes).unwrap();
1240 assert_eq!(response, Response::WriteMultipleCoils(0x3311, 5));
1241 }
1242
1243 #[test]
1244 fn read_input_registers() {
1245 let bytes = Bytes::from(vec![4, 0x06, 0xAA, 0x00, 0xCC, 0xBB, 0xEE, 0xDD]);
1246 let response = Response::try_from(bytes).unwrap();
1247 assert_eq!(
1248 response,
1249 Response::ReadInputRegisters(vec![0xAA00, 0xCCBB, 0xEEDD])
1250 );
1251 }
1252
1253 #[test]
1254 fn read_holding_registers() {
1255 let bytes = Bytes::from(vec![3, 0x04, 0xAA, 0x00, 0x11, 0x11]);
1256 let response = Response::try_from(bytes).unwrap();
1257 assert_eq!(
1258 response,
1259 Response::ReadHoldingRegisters(vec![0xAA00, 0x1111])
1260 );
1261 }
1262
1263 #[test]
1264 fn write_single_register() {
1265 let bytes = Bytes::from(vec![6, 0x00, 0x07, 0xAB, 0xCD]);
1266 let response = Response::try_from(bytes).unwrap();
1267 assert_eq!(response, Response::WriteSingleRegister(0x07, 0xABCD));
1268 }
1269
1270 #[test]
1271 fn write_multiple_registers() {
1272 let bytes = Bytes::from(vec![0x10, 0x00, 0x06, 0x00, 0x02]);
1273 let response = Response::try_from(bytes).unwrap();
1274 assert_eq!(response, Response::WriteMultipleRegisters(0x06, 2));
1275 }
1276
1277 #[test]
1278 fn report_server_id() {
1279 let bytes = Bytes::from(vec![0x11, 0x04, 0x042, 0xFF, 0x10, 0x20]);
1280 let response = Response::try_from(bytes).unwrap();
1281 assert_eq!(
1282 response,
1283 Response::ReportServerId(0x42, true, vec![0x10, 0x20])
1284 );
1285 }
1286
1287 #[test]
1288 fn masked_write_register() {
1289 let bytes = Bytes::from(vec![0x16, 0x00, 0x06, 0x80, 0x01, 0x40, 0x02]);
1290 let response = Response::try_from(bytes).unwrap();
1291 assert_eq!(response, Response::MaskWriteRegister(6, 0x8001, 0x4002));
1292 }
1293
1294 #[test]
1295 fn read_write_multiple_registers() {
1296 let bytes = Bytes::from(vec![0x17, 0x02, 0x12, 0x34]);
1297 let response = Response::try_from(bytes).unwrap();
1298 assert_eq!(response, Response::ReadWriteMultipleRegisters(vec![0x1234]));
1299 }
1300
1301 #[test]
1302 fn custom() {
1303 let bytes = Bytes::from(vec![0x55, 0xCC, 0x88, 0xAA, 0xFF]);
1304 let response = Response::try_from(bytes).unwrap();
1305 assert_eq!(
1306 response,
1307 Response::Custom(0x55, Bytes::from_static(&[0xCC, 0x88, 0xAA, 0xFF]))
1308 );
1309 }
1310 }
1311}