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