snap7_client/proto/s7commplus/
multivar.rs1use crate::proto::error::ProtoError;
2use crate::proto::s7commplus::data::DataArea;
3use crate::proto::s7commplus::session::{FC_GET_MULTI_VAR, FC_SET_MULTI_VAR, OPCODE_REQUEST};
4use bytes::{Buf, BufMut, Bytes, BytesMut};
5
6#[derive(Debug)]
7pub struct GetVarRequest {
8 pub seqnum: u16,
9 pub session_id: u32,
10 pub crc: u32,
11 pub lid: u32,
12}
13
14impl GetVarRequest {
15 pub fn encode(&self, buf: &mut BytesMut) {
16 let mut payload = BytesMut::with_capacity(9);
17 payload.put_u8(0x01); payload.put_u32(self.crc);
19 payload.put_u32(self.lid);
20 DataArea {
21 opcode: OPCODE_REQUEST,
22 function_code: FC_GET_MULTI_VAR,
23 seqnum: self.seqnum,
24 session_id: self.session_id,
25 transport_flags: 0,
26 payload: payload.freeze(),
27 }
28 .encode(buf);
29 }
30}
31
32#[derive(Debug)]
33pub struct GetVarResponse {
34 pub return_code: u8,
35 pub value: Bytes,
36}
37
38impl GetVarResponse {
39 pub fn decode(buf: &mut Bytes) -> Result<Self, ProtoError> {
40 let da = DataArea::decode(buf)?;
41 let mut payload = da.payload;
42 if payload.is_empty() {
43 return Err(ProtoError::BufferTooShort { need: 3, have: 0 });
44 }
45 let return_code = payload.get_u8();
46 if payload.len() < 2 {
47 return Err(ProtoError::BufferTooShort {
48 need: 2,
49 have: payload.len(),
50 });
51 }
52 let data_len = payload.get_u16() as usize;
53 if payload.len() < data_len {
54 return Err(ProtoError::BufferTooShort {
55 need: data_len,
56 have: payload.len(),
57 });
58 }
59 let value = payload.copy_to_bytes(data_len);
60 Ok(GetVarResponse { return_code, value })
61 }
62}
63
64#[derive(Debug)]
65pub struct SetVarRequest {
66 pub seqnum: u16,
67 pub session_id: u32,
68 pub crc: u32,
69 pub lid: u32,
70 pub value: Bytes,
71}
72
73impl SetVarRequest {
74 pub fn encode(&self, buf: &mut BytesMut) {
75 let mut payload = BytesMut::with_capacity(9 + 2 + self.value.len());
76 payload.put_u8(0x01); payload.put_u32(self.crc);
78 payload.put_u32(self.lid);
79 payload.put_u16(self.value.len() as u16);
80 payload.put_slice(&self.value);
81 DataArea {
82 opcode: OPCODE_REQUEST,
83 function_code: FC_SET_MULTI_VAR,
84 seqnum: self.seqnum,
85 session_id: self.session_id,
86 transport_flags: 0,
87 payload: payload.freeze(),
88 }
89 .encode(buf);
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use bytes::{Bytes, BytesMut};
97
98 #[test]
99 fn get_var_request_function_code() {
100 let req = GetVarRequest {
101 seqnum: 1,
102 session_id: 0xDEAD0001,
103 crc: 0xABCD1234,
104 lid: 2,
105 };
106 let mut buf = BytesMut::new();
107 req.encode(&mut buf);
108 assert_eq!(u16::from_be_bytes([buf[3], buf[4]]), 0x054C);
109 }
110
111 #[test]
112 fn get_var_request_session_id_position() {
113 let req = GetVarRequest {
114 seqnum: 2,
115 session_id: 0x12345678,
116 crc: 0xAABBCCDD,
117 lid: 1,
118 };
119 let mut buf = BytesMut::new();
120 req.encode(&mut buf);
121 let sid = u32::from_be_bytes([buf[9], buf[10], buf[11], buf[12]]);
123 assert_eq!(sid, 0x12345678);
124 }
125
126 #[test]
127 fn set_var_request_function_code() {
128 let req = SetVarRequest {
129 seqnum: 3,
130 session_id: 5,
131 crc: 0x11223344,
132 lid: 1,
133 value: Bytes::from_static(&[0x3F, 0x80, 0x00, 0x00]),
134 };
135 let mut buf = BytesMut::new();
136 req.encode(&mut buf);
137 assert_eq!(u16::from_be_bytes([buf[3], buf[4]]), 0x0542);
138 }
139
140 #[test]
141 fn get_var_response_decode() {
142 use bytes::BufMut;
143 let mut buf = BytesMut::new();
144 buf.put_u8(0x32);
145 buf.put_u16(0x0000);
146 buf.put_u16(0x054C);
147 buf.put_u16(0x0000);
148 buf.put_u16(0x0001);
149 buf.put_u32(0x00000005);
150 buf.put_u8(0x00);
151 buf.put_u8(0x0A); buf.put_u16(4);
153 buf.put_slice(&[0x3F, 0x80, 0x00, 0x00]);
154 let mut b = buf.freeze();
155 let resp = GetVarResponse::decode(&mut b).unwrap();
156 assert_eq!(resp.return_code, 0x0A);
157 assert_eq!(&resp.value[..], &[0x3F, 0x80, 0x00, 0x00]);
158 }
159}