Skip to main content

snap7_client/proto/s7commplus/
session.rs

1use crate::proto::error::ProtoError;
2use crate::proto::s7commplus::data::DataArea;
3use bytes::{Bytes, BytesMut};
4
5pub const FC_CREATE_OBJECT: u16 = 0x04CA;
6pub const FC_DELETE_OBJECT: u16 = 0x04D4;
7pub const FC_GET_MULTI_VAR: u16 = 0x054C;
8pub const FC_SET_MULTI_VAR: u16 = 0x0542;
9pub const FC_INIT_SSL: u16 = 0x05B3;
10
11pub const OPCODE_REQUEST: u8 = 0x31;
12pub const OPCODE_RESPONSE: u8 = 0x32;
13
14#[derive(Debug)]
15pub struct CreateObjectRequest {
16    pub seqnum: u16,
17}
18
19impl CreateObjectRequest {
20    pub fn new(seqnum: u16) -> Self {
21        Self { seqnum }
22    }
23
24    pub fn encode(&self, buf: &mut BytesMut) {
25        DataArea {
26            opcode: OPCODE_REQUEST,
27            function_code: FC_CREATE_OBJECT,
28            seqnum: self.seqnum,
29            session_id: 0,
30            transport_flags: 0,
31            payload: Bytes::from(vec![0u8; 64]),
32        }
33        .encode(buf);
34    }
35}
36
37#[derive(Debug)]
38pub struct CreateObjectResponse {
39    pub session_id: u32,
40    pub raw_payload: Bytes,
41}
42
43impl CreateObjectResponse {
44    pub fn decode(buf: &mut Bytes) -> Result<Self, ProtoError> {
45        let da = DataArea::decode(buf)?;
46        Ok(CreateObjectResponse {
47            session_id: da.session_id,
48            raw_payload: da.payload,
49        })
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56    use bytes::BytesMut;
57
58    #[test]
59    fn create_object_request_wire_length() {
60        let req = CreateObjectRequest::new(1);
61        let mut buf = BytesMut::new();
62        req.encode(&mut buf);
63        // 14-byte data area header + 64 zero bytes = 78
64        assert_eq!(buf.len(), 78);
65    }
66
67    #[test]
68    fn create_object_request_function_code() {
69        let req = CreateObjectRequest::new(1);
70        let mut buf = BytesMut::new();
71        req.encode(&mut buf);
72        // FC at bytes 3-4 (after opcode=1 + reserved=2)
73        assert_eq!(u16::from_be_bytes([buf[3], buf[4]]), 0x04CA);
74    }
75
76    #[test]
77    fn create_object_response_decode_from_bytes() {
78        use bytes::BufMut;
79        let session_id: u32 = 0x0000_001A;
80        let mut buf = BytesMut::new();
81        buf.put_u8(0x32); // opcode = response
82        buf.put_u16(0x0000); // reserved
83        buf.put_u16(0x04CA); // FC
84        buf.put_u16(0x0000); // reserved
85        buf.put_u16(0x0001); // seqnum
86        buf.put_u32(session_id);
87        buf.put_u8(0x00); // transport_flags
88        let mut b = buf.freeze();
89        let resp = CreateObjectResponse::decode(&mut b).unwrap();
90        assert_eq!(resp.session_id, session_id);
91    }
92}