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