modbus_core/codec/rtu/
server.rs

1//! Modbus RTU server (slave) specific functions.
2use super::*;
3
4/// Decode an RTU request.
5pub fn decode_request(buf: &[u8]) -> Result<Option<RequestAdu>> {
6    if buf.is_empty() {
7        return Ok(None);
8    }
9    decode(DecoderType::Request, buf)
10        .and_then(|frame| {
11            let Some((DecodedFrame { slave, pdu }, _frame_pos)) = frame else {
12                return Ok(None);
13            };
14            let hdr = Header { slave };
15            // Decoding of the PDU should are unlikely to fail due
16            // to transmission errors, because the frame's bytes
17            // have already been verified with the CRC.
18            Request::try_from(pdu)
19                .map(RequestPdu)
20                .map(|pdu| Some(RequestAdu { hdr, pdu }))
21                .map_err(|err| {
22                    // Unrecoverable error
23                    log::error!("Failed to decode request PDU: {err}");
24                    err
25                })
26        })
27        .map_err(|_| {
28            // Decoding the transport frame is non-destructive and must
29            // never fail!
30            unreachable!();
31        })
32}
33
34/// Encode an RTU response.
35pub fn encode_response(adu: ResponseAdu, buf: &mut [u8]) -> Result<usize> {
36    let ResponseAdu { hdr, pdu } = adu;
37    if buf.len() < 2 {
38        return Err(Error::BufferSize);
39    }
40    let len = pdu.encode(&mut buf[1..])?;
41    if buf.len() < len + 3 {
42        return Err(Error::BufferSize);
43    }
44    buf[0] = hdr.slave;
45    let crc = crc16(&buf[0..=len]);
46    BigEndian::write_u16(&mut buf[len + 1..], crc);
47    Ok(len + 3)
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn decode_empty_request() {
56        let req = decode_request(&[]).unwrap();
57        assert!(req.is_none());
58    }
59
60    #[test]
61    fn decode_partly_received_request() {
62        let buf = &[
63            0x12, // slave address
64            0x16, // function code
65        ];
66        let req = decode_request(buf).unwrap();
67        assert!(req.is_none());
68    }
69
70    #[test]
71    fn decode_write_single_register_request() {
72        let buf = &[
73            0x12, // slave address
74            0x06, // function code
75            0x22, // addr
76            0x22, // addr
77            0xAB, // value
78            0xCD, // value
79            0x9F, // crc
80            0xBE, // crc
81        ];
82        let adu = decode_request(buf).unwrap().unwrap();
83        let RequestAdu { hdr, pdu } = adu;
84        let RequestPdu(pdu) = pdu;
85        assert_eq!(hdr.slave, 0x12);
86        assert_eq!(FunctionCode::from(pdu), FunctionCode::WriteSingleRegister);
87    }
88
89    #[test]
90    fn encode_write_single_register_response() {
91        let adu = ResponseAdu {
92            hdr: Header { slave: 0x12 },
93            pdu: ResponsePdu(Ok(Response::WriteSingleRegister(0x2222, 0xABCD))),
94        };
95        let buf = &mut [0; 100];
96        let len = encode_response(adu, buf).unwrap();
97        assert_eq!(len, 8);
98        assert_eq!(buf[0], 0x12);
99        assert_eq!(buf[1], 0x06);
100        assert_eq!(buf[2], 0x22);
101        assert_eq!(buf[3], 0x22);
102        assert_eq!(buf[4], 0xAB);
103        assert_eq!(buf[5], 0xCD);
104        assert_eq!(buf[6], 0x9F);
105        assert_eq!(buf[7], 0xBE);
106    }
107}