modbus_core/codec/rtu/
client.rs1use super::*;
3
4pub fn encode_request(adu: RequestAdu, buf: &mut [u8]) -> Result<usize> {
6 let RequestAdu { hdr, pdu } = adu;
7 if buf.len() < 2 {
8 return Err(Error::BufferSize);
9 }
10 let len = pdu.encode(&mut buf[1..])?;
11 if buf.len() < len + 3 {
12 return Err(Error::BufferSize);
13 }
14 buf[0] = hdr.slave;
15 let crc = crc16(&buf[0..=len]);
16 BigEndian::write_u16(&mut buf[len + 1..], crc);
17 Ok(len + 3)
18}
19
20pub fn decode_response(buf: &[u8]) -> Result<Option<ResponseAdu>> {
22 if buf.is_empty() {
23 return Ok(None);
24 }
25 decode(DecoderType::Response, buf)
26 .and_then(|frame| {
27 let Some((DecodedFrame { slave, pdu }, _frame_pos)) = frame else {
28 return Ok(None);
29 };
30 let hdr = Header { slave };
31 ExceptionResponse::try_from(pdu)
36 .map(|er| ResponsePdu(Err(er)))
37 .or_else(|_| Response::try_from(pdu).map(|r| ResponsePdu(Ok(r))))
38 .map(|pdu| Some(ResponseAdu { hdr, pdu }))
39 .map_err(|err| {
40 log::error!("Failed to decode Response PDU: {err}");
42 err
43 })
44 })
45 .map_err(|_| {
46 unreachable!();
49 })
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[test]
57 fn decode_empty_response() {
58 let req = decode_response(&[]).unwrap();
59 assert!(req.is_none());
60 }
61
62 #[test]
63 fn decode_partly_received_response() {
64 let buf = &[
65 0x12, 0x16, ];
68 let req = decode_response(buf).unwrap();
69 assert!(req.is_none());
70 }
71
72 #[test]
73 fn encode_write_single_register_request() {
74 let mut buf = [0u8; 255];
75 let sz = encode_request(
76 RequestAdu {
77 hdr: Header { slave: 0x12 },
78 pdu: RequestPdu(Request::WriteSingleRegister(0x2222, 0xABCD)),
79 },
80 &mut buf,
81 )
82 .expect("Error encoding request");
83
84 let req = &buf[..sz];
85 assert_eq!(
86 req,
87 &[
88 0x12, 0x06, 0x22, 0x22, 0xAB, 0xCD, 0x9F, 0xBE, ]
97 );
98 }
99
100 #[test]
101 fn decode_write_single_register_response() {
102 use crate::frame::Response;
103 let rsp = &[0x12, 0x06, 0x22, 0x22, 0xAB, 0xCD, 0x9F, 0xBE];
104
105 assert!(matches!(
106 decode_response(rsp),
107 Ok(Some(ResponseAdu {
108 hdr: Header { slave: 0x12 },
109 pdu: ResponsePdu(Ok(Response::WriteSingleRegister(0x2222, 0xABCD)))
110 }))
111 ));
112 }
113
114 #[test]
115 fn decode_malformed_write_single_register_response() {
116 let rsp = &[0x12, 0x06, 0x22, 0x22, 0xAB, 0x65, 0x9E];
117
118 assert!(matches!(decode_response(rsp), Ok(None)));
119 }
120
121 #[test]
122 fn decode_bad_crc_write_single_register_response() {
123 let rsp = &[0x12, 0x06, 0x22, 0x22, 0xAB, 0xCD, 0x5F, 0xBE];
124
125 assert!(matches!(decode_response(rsp), Ok(None)));
126 }
127}