snap7_client/proto/s7commplus/
data.rs1use 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); buf.put_u16(self.function_code);
21 buf.put_u16(0x0000); 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); let function_code = buf.get_u16();
38 buf.advance(2); 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}