modbus_core/codec/
mod.rs

1use crate::{error::*, frame::*};
2use byteorder::{BigEndian, ByteOrder};
3
4pub mod rtu;
5pub mod tcp;
6
7/// The type of decoding
8#[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                // Here we have not information about the exact requested quantity
177                // therefore we just assume that the whole byte is meant.
178                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
222/// Encode a struct into a buffer.
223pub 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                // TODO:
323                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            // function code
557            assert_eq!(bytes[0], 0x10);
558
559            // write starting address
560            assert_eq!(bytes[1], 0x00);
561            assert_eq!(bytes[2], 0x06);
562
563            // quantity to write
564            assert_eq!(bytes[3], 0x00);
565            assert_eq!(bytes[4], 0x02);
566
567            // write byte count
568            assert_eq!(bytes[5], 0x04);
569
570            // values
571            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            // function code
587            assert_eq!(bytes[0], 0x17);
588
589            // read starting address
590            assert_eq!(bytes[1], 0x00);
591            assert_eq!(bytes[2], 0x05);
592
593            // quantity to read
594            assert_eq!(bytes[3], 0x00);
595            assert_eq!(bytes[4], 0x33);
596
597            // write starting address
598            assert_eq!(bytes[5], 0x00);
599            assert_eq!(bytes[6], 0x03);
600
601            // quantity to write
602            assert_eq!(bytes[7], 0x00);
603            assert_eq!(bytes[8], 0x02);
604
605            // write byte count
606            assert_eq!(bytes[9], 0x04);
607
608            // values
609            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, // byte count == 0
671            ];
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}