fennec_modbus/tcp/header.rs
1use bytes::{Buf, BufMut};
2
3use crate::{Error, protocol::codec, tcp::Header};
4
5pub struct Encoder;
6
7impl codec::Encode for Header {
8 /// Encode the header.
9 ///
10 /// # Example
11 ///
12 /// ```rust
13 /// use fennec_modbus::{
14 /// protocol::codec::Encode,
15 /// tcp::{Header, UnitId, header},
16 /// };
17 ///
18 /// const EXPECTED: &[u8] = &[
19 /// 0x15, 0x01, // transaction ID: high, low
20 /// 0x00, 0x00, // protocol ID
21 /// 0x00, 0x06, // length
22 /// 0xFF, // unit ID
23 /// ];
24 ///
25 /// let header = Header {
26 /// unit_id: UnitId::NonSignificant,
27 /// transaction_id: 0x1501,
28 /// length: 6,
29 /// protocol_id: 0,
30 /// };
31 /// let mut bytes = Vec::new();
32 /// header.encode(&mut bytes);
33 /// assert_eq!(bytes, EXPECTED);
34 /// ```
35 fn encode(&self, buf: &mut impl BufMut) {
36 buf.put_u16(self.transaction_id);
37 buf.put_u16(self.protocol_id);
38 buf.put_u16(self.length);
39 buf.put_u8(self.unit_id.into());
40 }
41}
42
43impl codec::Decode for Header {
44 /// Decode a header.
45 ///
46 /// # Example
47 ///
48 /// ```rust
49 /// use fennec_modbus::{
50 /// protocol::codec::Decode,
51 /// tcp::{Header, UnitId},
52 /// };
53 ///
54 /// let mut bytes: &[u8] = &[
55 /// 0x15, 0x01, // transaction ID: high, low
56 /// 0x00, 0x00, // protocol ID
57 /// 0x00, 0x06, // length
58 /// 0xFF, // unit ID
59 /// ];
60 /// let header = Header::decode(&mut bytes).unwrap();
61 ///
62 /// assert_eq!(header.transaction_id, 0x1501);
63 /// assert_eq!(header.protocol_id, 0);
64 /// assert_eq!(header.unit_id, UnitId::NonSignificant);
65 /// ```
66 fn decode(from: &mut impl Buf) -> Result<Self, Error> {
67 Ok(Self {
68 transaction_id: from.try_get_u16()?,
69 protocol_id: from.try_get_u16()?,
70 length: from.try_get_u16()?,
71 unit_id: from.try_get_u8()?.into(),
72 })
73 }
74}
75
76impl Header {
77 pub const N_BYTES: usize = 7;
78
79 /// Expected PDU length.
80 ///
81 /// TCP transport implementation should read exactly this number of codec
82 /// and parse as [`crate::protocol::Response`].
83 #[must_use]
84 pub const fn payload_length(&self) -> u16 {
85 self.length - 1
86 }
87}