Skip to main content

snap7_client/proto/s7commplus/
data.rs

1use crate::proto::error::ProtoError;
2use bytes::{Buf, BufMut, Bytes, BytesMut};
3
4const FIXED_LEN: usize = 14;
5
6#[derive(Debug, Clone)]
7pub struct DataArea {
8    pub opcode: u8,
9    pub function_code: u16,
10    pub seqnum: u16,
11    pub session_id: u32,
12    pub transport_flags: u8,
13    pub payload: Bytes,
14}
15
16impl DataArea {
17    pub fn encode(&self, buf: &mut BytesMut) {
18        buf.put_u8(self.opcode);
19        buf.put_u16(0x0000); // reserved
20        buf.put_u16(self.function_code);
21        buf.put_u16(0x0000); // reserved
22        buf.put_u16(self.seqnum);
23        buf.put_u32(self.session_id);
24        buf.put_u8(self.transport_flags);
25        buf.put_slice(&self.payload);
26    }
27
28    pub fn decode(buf: &mut Bytes) -> Result<Self, ProtoError> {
29        if buf.len() < FIXED_LEN {
30            return Err(ProtoError::BufferTooShort {
31                need: FIXED_LEN,
32                have: buf.len(),
33            });
34        }
35        let opcode = buf.get_u8();
36        buf.advance(2); // reserved
37        let function_code = buf.get_u16();
38        buf.advance(2); // reserved
39        let seqnum = buf.get_u16();
40        let session_id = buf.get_u32();
41        let transport_flags = buf.get_u8();
42        let payload = buf.copy_to_bytes(buf.remaining());
43        Ok(DataArea {
44            opcode,
45            function_code,
46            seqnum,
47            session_id,
48            transport_flags,
49            payload,
50        })
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57    use bytes::{Bytes, BytesMut};
58
59    fn sample() -> DataArea {
60        DataArea {
61            opcode: 0x31,
62            function_code: 0x04CA,
63            seqnum: 1,
64            session_id: 0,
65            transport_flags: 0,
66            payload: Bytes::from_static(&[0xDE, 0xAD]),
67        }
68    }
69
70    #[test]
71    fn data_area_encode_decode_roundtrip() {
72        let da = sample();
73        let mut buf = BytesMut::new();
74        da.encode(&mut buf);
75        let mut b = buf.freeze();
76        let decoded = DataArea::decode(&mut b).unwrap();
77        assert_eq!(decoded.opcode, 0x31);
78        assert_eq!(decoded.function_code, 0x04CA);
79        assert_eq!(decoded.seqnum, 1);
80        assert_eq!(decoded.session_id, 0);
81        assert_eq!(decoded.transport_flags, 0);
82        assert_eq!(&decoded.payload[..], &[0xDE, 0xAD]);
83    }
84
85    #[test]
86    fn data_area_encode_wire_bytes() {
87        let da = DataArea {
88            opcode: 0x31,
89            function_code: 0x04CA,
90            seqnum: 0x0001,
91            session_id: 0,
92            transport_flags: 0,
93            payload: Bytes::new(),
94        };
95        let mut buf = BytesMut::new();
96        da.encode(&mut buf);
97        assert_eq!(
98            &buf[..],
99            &[0x31, 0x00, 0x00, 0x04, 0xCA, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00]
100        );
101    }
102
103    #[test]
104    fn data_area_decode_truncated_returns_err() {
105        let mut b = Bytes::from_static(&[0x31, 0x00, 0x00]);
106        assert!(DataArea::decode(&mut b).is_err());
107    }
108}