modbus_core/codec/tcp/
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[7..])?;
14 if buf.len() < len + 7 {
15 return Err(Error::BufferSize);
16 }
17 buf[..2].copy_from_slice(&hdr.transaction_id.to_be_bytes());
18 buf[2..4].fill(0);
19 buf[4..6].copy_from_slice(&(1 + len as u16).to_be_bytes());
20 buf[6] = hdr.unit_id;
21 Ok(len + 7)
22}
23
24pub fn decode_response(buf: &[u8]) -> Result<Option<ResponseAdu<'_>>> {
26 if buf.is_empty() {
27 return Ok(None);
28 }
29 decode(DecoderType::Response, buf)
30 .and_then(|frame| {
31 let Some((
32 DecodedFrame {
33 transaction_id,
34 unit_id,
35 pdu,
36 },
37 _frame_pos,
38 )) = frame
39 else {
40 return Ok(None);
41 };
42 let hdr = Header {
43 transaction_id,
44 unit_id,
45 };
46 let response = ExceptionResponse::try_from(pdu)
50 .map(|er| ResponsePdu(Err(er)))
51 .or_else(|_| Response::try_from(pdu).map(|r| ResponsePdu(Ok(r))))
52 .map(|pdu| Some(ResponseAdu { hdr, pdu }));
53 #[cfg(feature = "log")]
54 if let Err(error) = response {
55 log::error!("Failed to decode Response PDU: {error}");
57 }
58 response
59 })
60 .map_err(|_| {
61 unreachable!();
64 })
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn decode_empty_response() {
73 let req = decode_response(&[]).unwrap();
74 assert!(req.is_none());
75 }
76
77 #[test]
78 fn decode_partly_received_response() {
79 let buf = &[
80 0x12, 0x16, ];
83 let req = decode_response(buf).unwrap();
84 assert!(req.is_none());
85 }
86
87 #[test]
88 fn encode_write_single_register_request() {
89 let mut buf = [0u8; 255];
90 let sz = encode_request(
91 RequestAdu {
92 hdr: Header {
93 transaction_id: 0x1234,
94 unit_id: 0x12,
95 },
96 pdu: RequestPdu(Request::WriteSingleRegister(0x2222, 0xABCD)),
97 },
98 &mut buf,
99 )
100 .expect("Error encoding request");
101
102 let req = &buf[..sz];
103 assert_eq!(
104 req,
105 &[
106 0x12, 0x34, 0x00, 0x00, 0x00, 0x06, 0x12, 0x06, 0x22, 0x22, 0xAB, 0xCD, ]
119 );
120 }
121
122 #[test]
123 fn decode_write_single_register_response() {
124 use crate::frame::Response;
125 let rsp = &[
126 0x12, 0x34, 0x00, 0x00, 0x00, 0x06, 0x12, 0x06, 0x22, 0x22, 0xAB, 0xCD,
127 ];
128
129 assert!(matches!(
130 decode_response(rsp),
131 Ok(Some(ResponseAdu {
132 hdr: Header {
133 transaction_id: 0x1234,
134 unit_id: 0x12
135 },
136 pdu: ResponsePdu(Ok(Response::WriteSingleRegister(0x2222, 0xABCD)))
137 }))
138 ));
139 }
140
141 #[test]
142 fn decode_malformed_write_single_register_response() {
143 let rsp = &[0x12, 0x06, 0x22, 0x22, 0xAB, 0x65, 0x9E];
144
145 assert!(matches!(decode_response(rsp), Ok(None)));
146 }
147
148 #[test]
149 fn decode_bad_crc_write_single_register_response() {
150 let rsp = &[0x12, 0x06, 0x22, 0x22, 0xAB, 0xCD, 0x5F, 0xBE];
151
152 assert!(matches!(decode_response(rsp), Ok(None)));
153 }
154}