Skip to main content

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}